{"id":20246374,"url":"https://github.com/montferret/lab","last_synced_at":"2025-10-25T12:03:37.561Z","repository":{"id":54452670,"uuid":"230943976","full_name":"MontFerret/lab","owner":"MontFerret","description":"Test runner for Ferret","archived":false,"fork":false,"pushed_at":"2023-03-28T19:12:40.000Z","size":369,"stargazers_count":12,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-10T21:13:42.931Z","etag":null,"topics":["data-mining","ferret","fql","go","golang","hacktoberfest","hacktoberfest2021","scraping","test-runner","tool"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MontFerret.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-12-30T16:08:47.000Z","updated_at":"2024-12-10T01:36:36.000Z","dependencies_parsed_at":"2024-01-23T21:20:46.476Z","dependency_job_id":"d2de4ec4-8f4f-4961-852a-d2845f5044ce","html_url":"https://github.com/MontFerret/lab","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MontFerret%2Flab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MontFerret%2Flab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MontFerret%2Flab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MontFerret%2Flab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MontFerret","download_url":"https://codeload.github.com/MontFerret/lab/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248298312,"owners_count":21080320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-mining","ferret","fql","go","golang","hacktoberfest","hacktoberfest2021","scraping","test-runner","tool"],"created_at":"2024-11-14T09:28:51.612Z","updated_at":"2025-10-25T12:03:37.555Z","avatar_url":"https://github.com/MontFerret.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lab - Ferret Test Runner\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://goreportcard.com/report/github.com/MontFerret/lab\"\u003e\n\t\t\u003cimg alt=\"Go Report Status\" src=\"https://goreportcard.com/badge/github.com/MontFerret/lab\"\u003e\n\t\u003c/a\u003e\n\u003c!-- \t\u003ca href=\"https://codecov.io/gh/MontFerret/lab\"\u003e\n\t\t\u003cimg alt=\"Code coverage\" src=\"https://codecov.io/gh/MontFerret/lab/branch/master/graph/badge.svg\" /\u003e\n\t\u003c/a\u003e --\u003e\n\t\u003ca href=\"https://discord.gg/kzet32U\"\u003e\n\t\t\u003cimg alt=\"Discord Chat\" src=\"https://img.shields.io/discord/501533080880676864.svg\"\u003e\n\t\u003c/a\u003e\n\t\u003ca href=\"https://github.com/MontFerret/lab/releases\"\u003e\n\t\t\u003cimg alt=\"Lab release\" src=\"https://img.shields.io/github/release/MontFerret/lab.svg\"\u003e\n\t\u003c/a\u003e\n\t\u003ca href=\"https://opensource.org/licenses/Apache-2.0\"\u003e\n\t\t\u003cimg alt=\"Apache-2.0 License\" src=\"http://img.shields.io/badge/license-Apache-brightgreen.svg\"\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\n**Lab** is a powerful, flexible test runner designed specifically for [Ferret](https://www.github.com/MontFerret/ferret) scripts. It enables automated testing of web scraping, browser automation, and API testing scenarios using Ferret Query Language (FQL).\n\n**🚀 Perfect for:**\n- End-to-end web application testing\n- Web scraping validation and monitoring  \n- API integration testing\n- Browser automation testing\n- Regression testing for web applications\n\nRead the introductory blog post about Lab [here!](https://www.montferret.dev/blog/say-hello-to-lab/)\n\n\u003cp align=\"center\"\u003e\n\u003cimg alt=\"lab\" src=\"https://raw.githubusercontent.com/MontFerret/lab/master/assets/landing.png\" style=\"margin-left: auto; margin-right: auto;\" width=\"495px\" height=\"501px\" /\u003e\n\u003c/p\u003e\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Test Suites](#test-suites)\n- [Advanced Usage](#advanced-usage)\n- [Configuration Reference](#configuration-reference)\n- [Architecture](#architecture)\n- [Development](#development)\n- [Best Practices](#best-practices)\n- [Troubleshooting](#troubleshooting)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n### 🏃‍♂️ **Performance \u0026 Scalability**\n- **Parallel execution** - Run multiple tests concurrently for faster feedback\n- **Configurable concurrency** - Control the number of simultaneous test executions\n- **Test retry mechanism** - Automatic retry of failed tests with customizable attempts\n- **Batch execution** - Run tests multiple times with configurable intervals\n\n### 🌐 **Flexible Runtime Support**\n- **Built-in Ferret runtime** - Execute tests using embedded Ferret engine\n- **Remote HTTP runtime** - Connect to remote Ferret services via HTTP/HTTPS\n- **External binary runtime** - Use custom Ferret CLI installations\n- **Multi-runtime testing** - Test against different Ferret versions or configurations\n\n### 📁 **Multiple Source Types**\n- **Local filesystem** - Execute scripts from local directories\n- **Git repositories** - Fetch and run tests directly from Git repos (HTTP/HTTPS)\n- **HTTP sources** - Download and execute scripts from web URLs\n- **Glob pattern matching** - Select multiple files using wildcard patterns\n\n### 🌍 **Static Content Serving**\n- **Built-in HTTP server** - Serve static files for testing web applications\n- **Multiple CDN endpoints** - Host different content on various paths\n- **Custom aliases** - Name your content endpoints for better organization\n- **Dynamic port allocation** - Automatically find available ports\n\n### 📊 **Rich Reporting \u0026 Monitoring**\n- **Multiple output formats** - Console and simple reporters available\n- **Detailed test results** - Comprehensive execution metrics and timing\n- **Wait conditions** - Test and wait for external services to be available\n- **Environment variable support** - Configure tests via environment variables\n\n## Installation\n\n### 📦 **Binary Downloads**\nDownload the latest pre-built binaries from our [releases page](https://github.com/MontFerret/lab/releases).\n\n**Linux:**\n```bash\ncurl -L https://github.com/MontFerret/lab/releases/latest/download/lab-linux-amd64.tar.gz | tar xz\nsudo mv lab /usr/local/bin/\n```\n\n**macOS:**\n```bash\ncurl -L https://github.com/MontFerret/lab/releases/latest/download/lab-darwin-amd64.tar.gz | tar xz\nsudo mv lab /usr/local/bin/\n```\n\n**Windows:**\nDownload the `.zip` file from releases and extract `lab.exe` to your PATH.\n\n### 🚀 **One-line Install Script**\nThe easiest way to install Lab on Unix-like systems:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/MontFerret/lab/master/install.sh | sh\n```\n\nThis script automatically:\n- Detects your operating system and architecture\n- Downloads the appropriate binary\n- Installs it to `/usr/local/bin/`\n- Makes it executable\n\n### 🐳 **Docker**\nRun Lab in a container without installing it locally:\n\n```bash\n# Pull the latest image\ndocker pull montferret/lab:latest\n\n# Run a simple test\ndocker run --rm -v $(pwd):/workspace montferret/lab:latest /workspace/tests/\n\n# With custom options\ndocker run --rm -v $(pwd):/workspace montferret/lab:latest \\\n    --concurrency=4 --reporter=simple /workspace/tests/\n```\n\n**Docker Compose Example:**\n```yaml\nversion: '3.8'\nservices:\n  lab:\n    image: montferret/lab:latest\n    volumes:\n      - ./tests:/workspace/tests\n      - ./static:/workspace/static\n    command: [\"--cdn=/workspace/static\", \"/workspace/tests/\"]\n```\n\n### 🛠️ **Build from Source**\nFor development or custom builds:\n\n```bash\n# Prerequisites: Go 1.23+ required\ngit clone https://github.com/MontFerret/lab.git\ncd lab\ngo build -o lab .\n\n# Or use the Makefile\nmake build\n```\n\n### ✅ **Verify Installation**\n```bash\nlab version\nlab --help\n```\n\n## Quick Start\n\n### 🎯 **Basic Usage**\n\nThe simplest way to run Ferret scripts with Lab:\n\n```bash\n# Execute a single FQL script\nlab myscript.fql\n\n# Run all FQL scripts in a directory\nlab myscripts/\n\n# Run with increased concurrency\nlab --concurrency=4 myscripts/\n\n# Run tests multiple times\nlab --times=3 myscript.fql\n```\n\n### 📝 **Your First Test**\n\nCreate a simple test file `example.fql`:\n\n```sql\nLET doc = DOCUMENT(\"https://www.github.com\", { \n    driver: \"cdp\",\n    userAgent: \"Lab Test Runner\" \n})\n\n// Wait for page to load\nWAIT_ELEMENT(doc, \"header\")\n\n// Extract page title\nLET title = doc.title\n\n// Return result\nRETURN {\n    url: doc.url,\n    title: title,\n    hasGitHubLogo: ELEMENT_EXISTS(doc, \"[aria-label*='GitHub']\")\n}\n```\n\nRun it:\n```bash\nlab example.fql\n```\n\n### 🎨 **Using Chrome DevTools Protocol**\n\nFor browser automation, you'll need a Chrome/Chromium instance running in headless mode:\n\n```bash\n# Start Chrome in headless mode (separate terminal)\ngoogle-chrome --headless --remote-debugging-port=9222\n\n# Run your tests (default CDP address)\nlab --cdp=http://127.0.0.1:9222 browser-tests/\n\n# Or use a custom CDP address\nlab --cdp=http://localhost:9223 browser-tests/\n```\n\n### 📊 **Example Output**\n\n```\n$ lab example.fql\n✓ example.fql (1.23s)\n  └─ Assertions: 1 passed, 0 failed\n\nTests: 1 passed, 0 failed\nTime:  1.23s\n```\n\n## Test Suites\n\nLab supports sophisticated test suites defined in YAML format, enabling you to create complex testing scenarios with assertions, parameters, and reusable components.\n\n### 📋 **Basic Test Suite Structure**\n\n```yaml\nquery:\n  text: |\n    LET doc = DOCUMENT(\"https://github.com/\", { driver: \"cdp\" })\n    \n    HOVER(doc, \".HeaderMenu-details\")\n    CLICK(doc, \".HeaderMenu a\")\n    \n    WAIT_NAVIGATION(doc)\n    WAIT_ELEMENT(doc, '.IconNav')\n    \n    FOR el IN ELEMENTS(doc, '.IconNav a')\n        RETURN TRIM(el.innerText)\n\nassert:\n  text: RETURN T::NOT::EMPTY(@lab.data.query.result)\n```\n\nSave as `github-test.yaml` and run:\n```bash\nlab github-test.yaml\n```\n\n### 🔗 **Reference External Scripts**\n\nKeep your FQL scripts separate and reference them in test suites:\n\n**navigation.fql:**\n```sql\nLET doc = DOCUMENT(@url, { driver: \"cdp\" })\nWAIT_ELEMENT(doc, \"body\")\nRETURN doc.title\n```\n\n**suite.yaml:**\n```yaml\nquery:\n  ref: ./scripts/navigation.fql\n  params:\n    url: \"https://example.com\"\n\nassert:\n  text: |\n    RETURN T::NOT::EMPTY(@lab.data.query.result) \n           AND T::CONTAINS(@lab.data.query.result, \"Example\")\n```\n\n### 🧪 **Complex Test Scenarios**\n\n```yaml\nname: \"E-commerce User Journey\"\ndescription: \"Test complete user purchase flow\"\n\nsetup:\n  text: |\n    LET baseUrl = \"https://demo-shop.example.com\"\n    RETURN { baseUrl }\n\nquery:\n  text: |\n    LET doc = DOCUMENT(@lab.data.setup.result.baseUrl, { driver: \"cdp\" })\n    \n    // Navigate to product\n    CLICK(doc, \".product-item:first-child a\")\n    WAIT_NAVIGATION(doc)\n    \n    // Add to cart\n    CLICK(doc, \".add-to-cart\")\n    WAIT_ELEMENT(doc, \".cart-confirmation\")\n    \n    // Go to checkout\n    CLICK(doc, \".checkout-btn\")\n    WAIT_NAVIGATION(doc)\n    \n    RETURN {\n      currentUrl: doc.url,\n      cartItems: LENGTH(ELEMENTS(doc, \".cart-item\")),\n      totalPrice: INNER_TEXT(doc, \".total-price\")\n    }\n\nassert:\n  text: |\n    LET result = @lab.data.query.result\n    RETURN T::CONTAINS(result.currentUrl, \"checkout\") \n           AND result.cartItems \u003e 0\n           AND T::NOT::EMPTY(result.totalPrice)\n\ncleanup:\n  text: |\n    // Clear cart or perform cleanup\n    RETURN \"Cleanup completed\"\n```\n\n### 🎯 **Parameterized Tests**\n\nCreate reusable test suites with parameters:\n\n```yaml\nquery:\n  text: |\n    LET doc = DOCUMENT(@testUrl, { \n      driver: \"cdp\",\n      timeout: @pageTimeout \n    })\n    \n    WAIT_ELEMENT(doc, @selector)\n    \n    RETURN {\n      title: doc.title,\n      elementExists: ELEMENT_EXISTS(doc, @selector)\n    }\n\nassert:\n  text: |\n    LET result = @lab.data.query.result\n    RETURN result.elementExists == true\n```\n\nRun with parameters:\n```bash\nlab --param=testUrl:\"https://example.com\" \\\n    --param=pageTimeout:5000 \\\n    --param=selector:\"h1\" \\\n    test-suite.yaml\n```\n\n### 📊 **Data-Driven Testing**\n\nUse external data sources for comprehensive testing:\n\n```yaml\nquery:\n  text: |\n    LET testData = [\n      { url: \"https://site1.com\", expectedTitle: \"Site 1\" },\n      { url: \"https://site2.com\", expectedTitle: \"Site 2\" }\n    ]\n    \n    FOR test IN testData\n      LET doc = DOCUMENT(test.url, { driver: \"cdp\" })\n      WAIT_ELEMENT(doc, \"title\")\n      \n      RETURN {\n        url: test.url,\n        expectedTitle: test.expectedTitle,\n        actualTitle: doc.title,\n        matches: doc.title == test.expectedTitle\n      }\n\nassert:\n  text: |\n    FOR result IN @lab.data.query.result\n      FILTER result.matches != true\n      RETURN false\n    \n    RETURN true\n```\n\n## Advanced Usage\n\n### 📁 **File Resolution**\n\nLab supports multiple source locations for maximum flexibility:\n\n#### **Local Files**\n```bash\n# Single file\nlab /path/to/test.fql\n\n# Directory with glob patterns\nlab \"tests/**/*.fql\"\nlab tests/integration/\n\n# Multiple paths\nlab --files=tests/unit/ --files=tests/integration/ --files=scripts/smoke.fql\n```\n\n#### **Git Repositories**\nFetch and execute tests directly from Git repositories:\n\n```bash\n# HTTPS Git repository\nlab git+https://github.com/username/test-repo.git//tests/\n\n# HTTP Git repository  \nlab git+http://git.example.com/tests.git//integration/\n\n# Specific branch or tag\nlab git+https://github.com/username/tests.git@v1.2.0//suite.yaml\n\n# Private repositories (requires authentication)\nlab git+https://username:token@github.com/private/repo.git//tests/\n```\n\n#### **HTTP Sources**\nDownload scripts from web URLs:\n\n```bash\n# Direct script URL\nlab https://raw.githubusercontent.com/user/repo/main/test.fql\n\n# Multiple HTTP sources\nlab https://example.com/tests/suite1.yaml https://example.com/tests/suite2.yaml\n```\n\n### 🌐 **Static File Serving (CDN)**\n\nLab includes a built-in HTTP server for serving static content during tests:\n\n#### **Basic CDN Usage**\n```bash\n# Serve files from ./website directory\nlab --cdn=./website tests/\n\n# Access in your FQL scripts\nLET doc = DOCUMENT(@lab.cdn.website, { driver: \"cdp\" })\n```\n\n#### **Multiple CDN Endpoints**\n```bash\n# Serve multiple directories\nlab --cdn=./app --cdn=./api-mocks tests/\n```\n\nFQL Script:\n```sql\n// Access different endpoints\nLET appPage = DOCUMENT(@lab.cdn.app, { driver: \"cdp\" })\nLET apiData = DOCUMENT(@lab.cdn.api-mocks + \"/users.json\")\n```\n\n#### **Custom CDN Aliases**\n```bash\n# Give custom names to your content\nlab --cdn=./frontend@app --cdn=./mockdata@api tests/\n```\n\nFQL Script:\n```sql\n// Use custom aliases\nLET homePage = DOCUMENT(@lab.cdn.app + \"/index.html\", { driver: \"cdp\" })\nLET userData = DOCUMENT(@lab.cdn.api + \"/user/123.json\")\n```\n\n#### **Advanced CDN Example**\n```bash\n# Complex setup with multiple content sources\nlab \\\n  --cdn=./dist@webapp \\\n  --cdn=./test-fixtures@fixtures \\\n  --cdn=./mock-apis@mocks \\\n  --concurrency=3 \\\n  tests/e2e/\n```\n\n### 🔄 **Remote Ferret Runtime**\n\nLab can execute tests against remote Ferret instances instead of using the built-in runtime:\n\n#### **HTTP/HTTPS Runtime**\n```bash\n# Connect to remote Ferret service\nlab --runtime=https://ferret.example.com/api tests/\n\n# With custom headers and path\nlab \\\n  --runtime=https://ferret.example.com \\\n  --runtime-param=headers:'{\"Authorization\": \"Bearer token123\"}' \\\n  --runtime-param=path:\"/v1/execute\" \\\n  tests/\n```\n\nThe HTTP runtime sends POST requests with:\n```json\n{\n  \"query\": \"FQL script content\",\n  \"params\": {\n    \"key\": \"value\"\n  }\n}\n```\n\n#### **External Binary Runtime**\nUse custom Ferret CLI installations:\n\n```bash\n# Use specific Ferret binary\nlab --runtime=bin:./custom-ferret tests/\n\n# With additional parameters\nlab \\\n  --runtime=bin:/usr/local/bin/ferret-v0.18 \\\n  --runtime-param=timeout:30 \\\n  tests/\n```\n\n#### **Runtime Comparison Testing**\nTest against multiple runtime versions:\n\n```bash\n# Test with built-in runtime\nlab tests/ \u003e builtin-results.txt\n\n# Test with remote runtime\nlab --runtime=https://ferret-v0.17.example.com tests/ \u003e remote-v0.17-results.txt\n\n# Compare results\ndiff builtin-results.txt remote-v0.17-results.txt\n```\n\n### ⚡ **Performance Optimization**\n\n#### **Parallel Execution**\n```bash\n# Run up to 8 tests simultaneously\nlab --concurrency=8 tests/\n\n# Balance between speed and resource usage\nlab --concurrency=4 --timeout=60 large-test-suite/\n```\n\n#### **Test Repetition \u0026 Retry**\n```bash\n# Run each test 3 times for reliability testing\nlab --times=3 tests/flaky/\n\n# Retry failed tests up to 2 additional times\nlab --attempts=3 tests/\n\n# Add delay between test cycles\nlab --times=5 --times-interval=10 stress-tests/\n```\n\n#### **Conditional Execution**\n```bash\n# Wait for services to be available before running tests\nlab \\\n  --wait=http://127.0.0.1:9222/json/version \\\n  --wait=postgres://localhost:5432/testdb \\\n  --wait-timeout=30 \\\n  tests/integration/\n``` \n\n## Configuration Reference\n\n### 🎛️ **Command Line Flags**\n\n| Flag | Short | Environment Variable | Default | Description |\n|------|-------|---------------------|---------|-------------|\n| `--files` | `-f` | `LAB_FILES` | - | Location of FQL script files to run |\n| `--timeout` | `-t` | `LAB_TIMEOUT` | `30` | Test timeout in seconds |\n| `--cdp` | - | `LAB_CDP` | `http://127.0.0.1:9222` | Chrome DevTools Protocol address |\n| `--reporter` | - | `LAB_REPORTER` | `console` | Output reporter (`console`, `simple`) |\n| `--runtime` | `-r` | `LAB_RUNTIME` | - | URL to remote Ferret runtime |\n| `--runtime-param` | `--rp` | `LAB_RUNTIME_PARAM` | - | Parameters for remote runtime |\n| `--concurrency` | `-c` | `LAB_CONCURRENCY` | `1` | Number of parallel test executions |\n| `--times` | - | `LAB_TIMES` | `1` | Number of times to run each test |\n| `--attempts` | `-a` | `LAB_ATTEMPTS` | `1` | Number of retry attempts for failed tests |\n| `--times-interval` | - | `LAB_TIMES_INTERVAL` | `0` | Interval between test cycles (seconds) |\n| `--cdn` | - | `LAB_CDN` | - | Directory to serve via HTTP |\n| `--param` | `-p` | `LAB_PARAM` | - | Query parameters for tests |\n| `--wait` | `-w` | `LAB_WAIT` | - | Wait for resource availability |\n| `--wait-timeout` | `--wt` | `LAB_WAIT_TIMEOUT` | `5` | Wait timeout in seconds |\n| `--wait-attempts` | - | `LAB_WAIT_ATTEMPTS` | `5` | Number of wait attempts |\n\n### 🌍 **Environment Variables**\n\nSet environment variables for consistent configuration across environments:\n\n```bash\n# Basic configuration\nexport LAB_TIMEOUT=60\nexport LAB_CONCURRENCY=4\nexport LAB_REPORTER=simple\n\n# CDP configuration\nexport LAB_CDP=http://chrome-headless:9222\n\n# Runtime configuration  \nexport LAB_RUNTIME=https://ferret-api.example.com\nexport LAB_RUNTIME_PARAM='headers:{\"API-Key\":\"secret123\"}'\n\n# Run tests\nlab tests/\n```\n\n### 📝 **Configuration Examples**\n\n#### **CI/CD Configuration**\n```bash\n#!/bin/bash\n# ci-test.sh\n\n# Set CI-friendly defaults\nexport LAB_TIMEOUT=120\nexport LAB_CONCURRENCY=2\nexport LAB_REPORTER=simple\nexport LAB_ATTEMPTS=3\n\n# Wait for services\nlab \\\n  --wait=http://app:3000/health \\\n  --wait=postgres://db:5432/testdb \\\n  --wait-timeout=60 \\\n  tests/integration/\n```\n\n#### **Local Development**\n```bash\n#!/bin/bash\n# dev-test.sh\n\nexport LAB_CDP=http://localhost:9222\nexport LAB_TIMEOUT=30\nexport LAB_CONCURRENCY=1\n\n# Serve local assets and run tests\nlab \\\n  --cdn=./dist@app \\\n  --cdn=./fixtures@data \\\n  tests/dev/\n```\n\n#### **Load Testing**\n```bash\n#!/bin/bash\n# load-test.sh\n\n# High concurrency for performance testing\nlab \\\n  --concurrency=20 \\\n  --times=100 \\\n  --times-interval=1 \\\n  --timeout=10 \\\n  tests/performance/\n```\n\n### ⚙️ **Runtime Parameters**\n\nConfigure remote Ferret runtime behavior:\n\n```bash\n# HTTP runtime with custom headers\nlab \\\n  --runtime=https://ferret.api.com \\\n  --runtime-param='headers:{\"Authorization\":\"Bearer token\"}' \\\n  --runtime-param='path:\"/v2/execute\"' \\\n  --runtime-param='timeout:30' \\\n  tests/\n\n# Binary runtime with custom flags\nlab \\\n  --runtime=bin:/usr/local/bin/ferret \\\n  --runtime-param='flags:[\"--timeout=60\", \"--verbose\"]' \\\n  tests/\n```\n\n## Architecture\n\n### 🏗️ **System Overview**\n\nLab is built with a modular architecture that separates concerns and enables flexible testing scenarios:\n\n```\n┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐\n│   Test Sources  │    │   Test Runner   │    │   Ferret        │\n│                 │    │                 │    │   Runtime       │\n│ • File System   │───▶│ • Orchestration │───▶│                 │\n│ • Git Repos     │    │ • Parallelization│    │ • Built-in      │\n│ • HTTP URLs     │    │ • Retry Logic   │    │ • Remote HTTP   │\n└─────────────────┘    │ • Reporting     │    │ • External Bin  │\n                       └─────────────────┘    └─────────────────┘\n                                │\n                                ▼\n                       ┌─────────────────┐\n                       │   CDN Server    │\n                       │                 │\n                       │ • Static Files  │\n                       │ • Multi-tenant  │\n                       │ • Auto Ports    │\n                       └─────────────────┘\n```\n\n### 📦 **Core Components**\n\n#### **Sources (`sources/`)**\nHandles fetching test files from various locations:\n- **FileSystem Source**: Local directory and file access with glob pattern support\n- **Git Source**: Clone and fetch files from Git repositories (HTTP/HTTPS)\n- **HTTP Source**: Download scripts from web URLs\n- **Aggregate Source**: Combines multiple source types\n\n#### **Runtime (`runtime/`)**\nManages Ferret script execution:\n- **Built-in Runtime**: Uses embedded Ferret engine (default)\n- **Remote Runtime**: HTTP-based communication with remote Ferret services\n- **Binary Runtime**: Executes external Ferret CLI binaries\n\n#### **Test Runner (`runner/`)**\nOrchestrates test execution:\n- **Parallel Processing**: Manages concurrent test execution\n- **Retry Mechanism**: Handles failed test retries\n- **Resource Management**: Controls timeouts and resource allocation\n- **Lifecycle Management**: Handles setup, execution, and cleanup phases\n\n#### **CDN Server (`cdn/`)**\nBuilt-in HTTP server for static content:\n- **Multi-endpoint**: Serve multiple directories simultaneously\n- **Dynamic Ports**: Automatic port allocation to avoid conflicts\n- **Alias Support**: Custom naming for endpoints\n\n#### **Reporters (`reporters/`)**\nOutput formatting and result presentation:\n- **Console Reporter**: Rich, colored output for interactive use\n- **Simple Reporter**: Plain text output suitable for CI/CD\n\n#### **Testing Framework (`testing/`)**\nTest suite definition and validation:\n- **YAML Parser**: Parse test suite definitions\n- **Parameter Injection**: Handle runtime parameters and data binding\n- **Assertion Engine**: Validate test results\n\n### 🔄 **Execution Flow**\n\n1. **Input Processing**: Parse command-line arguments and environment variables\n2. **Source Resolution**: Fetch test files from specified sources\n3. **CDN Initialization**: Start HTTP servers for static content (if needed)  \n4. **Runtime Setup**: Initialize Ferret runtime (built-in or remote)\n5. **Test Discovery**: Find and parse test files and suites\n6. **Parallel Execution**: Run tests according to concurrency settings\n7. **Result Collection**: Gather execution results and timing data\n8. **Reporting**: Format and output results via selected reporter\n9. **Cleanup**: Stop CDN servers and clean up resources\n\n### 🎯 **Design Principles**\n\n- **Modularity**: Each component has a single responsibility\n- **Extensibility**: Easy to add new source types, runtimes, or reporters\n- **Performance**: Optimized for parallel execution and resource efficiency\n- **Reliability**: Built-in retry mechanisms and error handling\n- **Flexibility**: Support for various deployment scenarios and configurations\n\n## Development\n\n### 🛠️ **Building from Source**\n\n**Prerequisites:**\n- Go 1.23 or later\n- Git\n\n**Build Steps:**\n```bash\n# Clone the repository\ngit clone https://github.com/MontFerret/lab.git\ncd lab\n\n# Install development tools\nmake install-tools\n\n# Build the project\nmake build\n# Or manually:\ngo build -o bin/lab -ldflags \"-X main.version=dev\" ./main.go\n```\n\n**Development Workflow:**\n```bash\n# Run tests\nmake test\n# Or:\ngo test ./...\n\n# Format code\nmake fmt\n\n# Lint code\nmake lint\n\n# Run all checks (vet, test, compile)\nmake build\n```\n\n### 🧪 **Testing Lab Itself**\n\n```bash\n# Run unit tests\ngo test -v ./...\n\n# Run specific test suites\ngo test -v ./sources/...\ngo test -v ./runtime/...\n\n# Run tests with coverage\nmake cover\n```\n\n### 🏗️ **Project Structure**\n\n```\nlab/\n├── main.go              # Application entry point\n├── cmd/                 # CLI command implementations\n├── cdn/                 # Static file server\n├── reporters/           # Output formatters\n├── runner/              # Test execution orchestration  \n├── runtime/             # Ferret runtime implementations\n├── sources/             # Test file source handlers\n├── testing/             # Test suite definitions\n├── assets/              # Documentation assets\n├── Dockerfile          # Container build definition\n├── Makefile            # Build automation\n└── README.md           # This file\n```\n\n### 📚 **Adding New Features**\n\n#### **New Source Type**\n1. Implement the `Source` interface in `sources/`\n2. Add URL scheme handling in `sources/source.go`\n3. Add tests in `sources/`\n\n#### **New Runtime**\n1. Implement the `Runtime` interface in `runtime/`\n2. Add runtime type detection in `runtime/runtime.go`\n3. Add configuration handling\n\n#### **New Reporter**\n1. Implement the `Reporter` interface in `reporters/`\n2. Register the reporter in CLI flags\n3. Add output format tests\n\n## Best Practices\n\n### 📋 **Test Organization**\n\n#### **Directory Structure**\n```\ntests/\n├── unit/              # Unit tests for individual components\n│   ├── api/\n│   └── ui/\n├── integration/       # Integration tests\n│   ├── user-flows/\n│   └── data-validation/\n├── e2e/              # End-to-end tests\n│   ├── critical-path/\n│   └── smoke/\n├── fixtures/         # Test data and assets\n│   ├── pages/\n│   └── data/\n└── scripts/          # Reusable FQL scripts\n    ├── common/\n    └── helpers/\n```\n\n#### **Naming Conventions**\n- Use descriptive test names: `user-registration-flow.yaml`\n- Prefix test types: `smoke-`, `regression-`, `load-`\n- Use kebab-case for files: `checkout-process.fql`\n\n#### **Test Suite Best Practices**\n```yaml\n# Good: Descriptive names and clear structure\nname: \"User Authentication Flow\"\ndescription: \"Verify user login, logout, and session management\"\n\nsetup:\n  text: |\n    // Clear any existing sessions\n    // Set up test data\n    \nquery:\n  text: |\n    // Main test logic with clear comments\n    \nassert:\n  text: |\n    // Specific, meaningful assertions\n    \ncleanup:\n  text: |\n    // Clean up test data\n```\n\n### ⚡ **Performance Optimization**\n\n#### **Concurrency Guidelines**\n```bash\n# Local development: Low concurrency\nlab --concurrency=2 tests/\n\n# CI environments: Medium concurrency  \nlab --concurrency=4 tests/\n\n# Dedicated test infrastructure: High concurrency\nlab --concurrency=8 tests/\n```\n\n#### **Resource Management**\n- Use appropriate timeouts for different test types\n- Implement proper cleanup in test suites\n- Monitor memory usage with large test suites\n- Use CDN for shared static assets\n\n#### **Test Efficiency**\n```bash\n# Run faster tests first\nlab tests/smoke/ \u0026\u0026 lab tests/integration/ \u0026\u0026 lab tests/e2e/\n\n# Use tags for test categorization\nlab tests/critical/ --timeout=60\nlab tests/extended/ --timeout=300 --concurrency=1\n```\n\n### 🔒 **Security Considerations**\n\n- Never commit sensitive data in test files\n- Use environment variables for credentials\n- Sanitize test outputs that might contain secrets\n- Use separate test environments for security testing\n\n```bash\n# Good: Use environment variables\nexport TEST_API_KEY=\"your-key-here\"\nlab --param=apiKey:$TEST_API_KEY tests/\n\n# Bad: Hardcode in scripts\n# Don't do this: LET apiKey = \"secret-key-123\"\n```\n\n## Troubleshooting\n\n### 🐛 **Common Issues**\n\n#### **Chrome/CDP Connection Issues**\n```\nError: Failed to connect to CDP at http://127.0.0.1:9222\n```\n\n**Solutions:**\n1. **Start Chrome in headless mode:**\n   ```bash\n   google-chrome --headless --remote-debugging-port=9222 --no-sandbox\n   ```\n\n2. **Check if Chrome is running:**\n   ```bash\n   curl http://127.0.0.1:9222/json/version\n   ```\n\n3. **Use custom CDP address:**\n   ```bash\n   lab --cdp=http://localhost:9223 tests/\n   ```\n\n#### **Test Timeouts**\n```\nError: Test timed out after 30 seconds\n```\n\n**Solutions:**\n1. **Increase timeout:**\n   ```bash\n   lab --timeout=60 tests/\n   ```\n\n2. **Optimize test scripts:**\n   ```sql\n   -- Add explicit waits\n   WAIT_ELEMENT(doc, \".loading\", { displayed: false })\n   \n   -- Use shorter timeouts for quick checks\n   WAIT_ELEMENT(doc, \".button\", { timeout: 5000 })\n   ```\n\n#### **Git Source Issues**\n```\nError: Failed to clone repository\n```\n\n**Solutions:**\n1. **Check repository URL:**\n   ```bash\n   git clone https://github.com/user/repo.git  # Test manually\n   ```\n\n2. **Authentication for private repos:**\n   ```bash\n   lab git+https://username:token@github.com/private/repo.git//tests/\n   ```\n\n3. **Use SSH for private repos:**\n   ```bash\n   # Set up SSH keys, then:\n   lab git+ssh://git@github.com/private/repo.git//tests/\n   ```\n\n#### **CDN Port Conflicts**\n```\nError: Failed to start CDN server on port 8080\n```\n\n**Solutions:**\n1. **Lab automatically finds free ports**, but you can specify:**\n   ```bash\n   lab --cdn=./static@app:8081 tests/\n   ```\n\n2. **Check for port conflicts:**\n   ```bash\n   netstat -tlnp | grep :8080\n   ```\n\n### 📊 **Performance Issues**\n\n#### **High Memory Usage**\n- Reduce concurrency: `--concurrency=2`\n- Implement proper cleanup in tests\n- Use external binary runtime for memory-intensive tests\n\n#### **Slow Test Execution**\n- Enable parallel execution: `--concurrency=4`\n- Use local CDN for static assets\n- Optimize FQL scripts for better performance\n- Profile tests to identify bottlenecks\n\n### 🔍 **Debugging Tips**\n\n#### **Verbose Output**\n```bash\n# Enable detailed logging (if available)\nexport LOG_LEVEL=debug\nlab tests/\n\n# Use simple reporter for cleaner output\nlab --reporter=simple tests/\n```\n\n#### **Test Individual Scripts**\n```bash\n# Test one file at a time\nlab specific-test.fql\n\n# Run with retries disabled\nlab --attempts=1 problematic-test.fql\n```\n\n#### **Validate Test Syntax**\n```bash\n# Test FQL syntax with Ferret CLI\nferret -q \"RETURN 1\"  # Should return [1]\n```\n\n## Contributing\n\n### 🤝 **How to Contribute**\n\nWe welcome contributions to Lab! Here's how to get started:\n\n1. **Fork the repository** on GitHub\n2. **Create a feature branch**: `git checkout -b feature/awesome-feature`\n3. **Make your changes** and add tests\n4. **Run the test suite**: `make test`\n5. **Commit your changes**: `git commit -am 'Add awesome feature'`\n6. **Push to the branch**: `git push origin feature/awesome-feature`\n7. **Submit a pull request**\n\n### 📝 **Development Guidelines**\n\n- **Write tests** for new features\n- **Follow Go conventions** and formatting (`make fmt`)\n- **Pass all linting checks** (`make lint`)\n- **Update documentation** for user-facing changes\n- **Keep commits atomic** and write clear commit messages\n\n### 🐛 **Reporting Issues**\n\nWhen reporting bugs, please include:\n- Lab version (`lab version`)\n- Operating system and version\n- Go version (if building from source)\n- Complete command that failed\n- Full error message and stack trace\n- Minimal reproduction case\n\n### 💡 **Feature Requests**\n\nBefore requesting features:\n- Check existing issues and discussions\n- Describe the use case and problem you're solving\n- Consider if it fits Lab's scope and philosophy\n- Be prepared to help with implementation\n\n### 🔄 **Development Process**\n\n1. **Discussion**: Major features should be discussed in issues first\n2. **Implementation**: Write code with tests and documentation\n3. **Review**: Submit PR for code review\n4. **Testing**: Ensure all CI checks pass\n5. **Merge**: Maintainer will merge when ready\n\n## License\n\nLab is licensed under the [Apache License 2.0](LICENSE).\n\n---\n\n**Happy Testing!** 🚀\n\nFor more information about Ferret and FQL, visit the [Ferret documentation](https://www.montferret.dev/docs/).\n\nJoin our community on [Discord](https://discord.gg/kzet32U) for support and discussions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmontferret%2Flab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmontferret%2Flab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmontferret%2Flab/lists"}