{"id":47795025,"url":"https://github.com/eclipse-score/itf","last_synced_at":"2026-04-03T16:13:53.123Z","repository":{"id":274807436,"uuid":"922929670","full_name":"eclipse-score/itf","owner":"eclipse-score","description":"Integration Testing Framework repository","archived":false,"fork":false,"pushed_at":"2026-03-23T08:56:51.000Z","size":375,"stargazers_count":0,"open_issues_count":3,"forks_count":14,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-03-24T06:10:46.134Z","etag":null,"topics":["itf","score","testing"],"latest_commit_sha":null,"homepage":"https://eclipse-score.github.io/itf","language":"Python","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/eclipse-score.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-27T10:49:56.000Z","updated_at":"2026-03-23T08:56:54.000Z","dependencies_parsed_at":"2025-02-25T14:27:36.810Z","dependency_job_id":"c827288a-34f3-41b7-b7a5-8667d5b9d1d9","html_url":"https://github.com/eclipse-score/itf","commit_stats":null,"previous_names":["eclipse-score/itf"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/eclipse-score/itf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipse-score%2Fitf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipse-score%2Fitf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipse-score%2Fitf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipse-score%2Fitf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eclipse-score","download_url":"https://codeload.github.com/eclipse-score/itf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipse-score%2Fitf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31362716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T15:19:21.178Z","status":"ssl_error","status_checked_at":"2026-04-03T15:19:20.670Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["itf","score","testing"],"created_at":"2026-04-03T16:13:52.509Z","updated_at":"2026-04-03T16:13:53.114Z","avatar_url":"https://github.com/eclipse-score.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n*******************************************************************************\nCopyright (c) 2025 Contributors to the Eclipse Foundation\nSee the NOTICE file(s) distributed with this work for additional\ninformation regarding copyright ownership.\nThis program and the accompanying materials are made available under the\nterms of the Apache License Version 2.0 which is available at\nhttps://www.apache.org/licenses/LICENSE-2.0\nSPDX-License-Identifier: Apache-2.0\n*******************************************************************************\n--\u003e\n# Integration Test Framework (ITF)\n\nITF is a [`pytest`](https://docs.pytest.org/en/latest/contents.html)-based testing framework designed for ECU (Electronic Control Unit) testing in automotive domains. It provides a flexible, plugin-based architecture that enables testing on multiple target environments including Docker containers, QEMU virtual machines, and real hardware.\n\n## Key Features\n\n- **Plugin-Based Architecture**: Modular design with support for Docker, QEMU, DLT, and custom plugins\n- **Target Abstraction**: Unified `Target` interface with capability-based system for different test environments\n- **Flexible Testing**: Write tests once, run across multiple targets (Docker, QEMU, hardware)\n- **Capability System**: Tests can query and adapt based on available target capabilities\n- **Bazel Integration**: Seamless integration with Bazel build system via `py_itf_test` macro\n\n## Quick Start\n\n### Installation\n\nAdd ITF to your `MODULE.bazel`:\n```starlark\nbazel_dep(name = \"score_itf\", version = \"0.1.0\")\n```\n\nConfigure your `.bazelrc`:\n```\ncommon --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/\ncommon --registry=https://bcr.bazel.build\n```\n\n### Basic Test Example\n\n```python\n# test_example.py\nfrom score.itf.core.com.ssh import execute_command\n\ndef test_ssh_connection(target):\n    with target.ssh() as ssh:\n        execute_command(ssh, \"echo 'Hello from target!'\")\n```\n\n### BUILD Configuration\n\n```starlark\nload(\"//:defs.bzl\", \"py_itf_test\")\nload(\"//score/itf/plugins:plugins.bzl\", \"docker\")\n\npy_itf_test(\n    name = \"test_example\",\n    srcs = [\"test_example.py\"],\n    args = [\"--docker-image=ubuntu:24.04\"],\n    plugins = [docker],\n)\n```\n\n## Architecture\n\n### Target System\n\nITF uses a capability-based target system. The `Target` base class provides a common interface that all target implementations extend:\n\n```python\nfrom score.itf.plugins.core import Target\n\nclass MyTarget(Target):\n    def __init__(self):\n        super().__init__(capabilities={'ssh', 'sftp', 'exec'})\n```\n\nTests can check for capabilities and adapt accordingly:\n\n```python\nfrom score.itf.plugins.core import requires_capabilities\n\n@requires_capabilities(\"exec\")\ndef test_docker_command(target):\n    exit_code, output = target.execute(\"ls -la\")\n    assert exit_code == 0\n\n@requires_capabilities(\"ssh\", \"sftp\")\ndef test_file_transfer(target):\n    with target.ssh() as ssh:\n        # SSH operations\n        pass\n```\n\n### Plugin System\n\nITF supports modular plugins that extend functionality:\n\n- **`core`**: Basic functionality that is the entry point for plugin extensions and hooks\n- **`docker`**: Docker container targets with `exec` capability\n- **`qemu`**: QEMU virtual machine targets with `ssh` and `sftp` capabilities\n- **`dlt`**: DLT (Diagnostic Log and Trace) message capture and analysis\n\n## Writing Tests\n\n### Basic Test Structure\n\nTests receive a `target` fixture that provides access to the target environment:\n\n```python\ndef test_basic(target):\n    # Use target methods based on capabilities\n    if target.has_capability(\"ssh\"):\n        with target.ssh() as ssh:\n            # Perform SSH operations\n            pass\n```\n\n### Docker Tests\n\n```python\ndef test_docker_exec(target):\n    exit_code, output = target.execute(\"uname -a\")\n    assert exit_code == 0\n    assert b\"Linux\" in output\n```\n\nBUILD file:\n```starlark\npy_itf_test(\n    name = \"test_docker\",\n    srcs = [\"test_docker.py\"],\n    args = [\"--docker-image=ubuntu:24.04\"],\n    plugins = [docker],\n)\n```\n\n### QEMU Tests\n\n```python\nfrom score.itf.core.com.ssh import execute_command\n\ndef test_qemu_ssh(target):\n    with target.ssh(username=\"root\", password=\"\") as ssh:\n        result = execute_command(ssh, \"uname -a\")\n```\n\nBUILD file:\n```starlark\npy_itf_test(\n    name = \"test_qemu\",\n    srcs = [\"test_qemu.py\"],\n    args = [\n        \"--qemu-image=$(location //path:qemu_image)\",\n        \"--qemu-config=$(location qemu_config.json)\",\n    ],\n    data = [\n        \"//path:qemu_image\",\n        \"qemu_config.json\",\n    ],\n    plugins = [qemu],\n)\n```\n\nQEMU targets are configured using a JSON configuration file that specifies network settings, resource allocation, and other parameters:\n\n```json\n{\n    \"networks\": [\n        {\n            \"name\": \"tap0\",\n            \"ip_address\": \"169.254.158.190\",\n            \"gateway\": \"169.254.21.88\"\n        }\n    ],\n    \"ssh_port\": 22,\n    \"qemu_num_cores\": 2,\n    \"qemu_ram_size\": \"1G\"\n}\n```\n\n\n### Capability-Based Tests\n\nThe `@requires_capabilities` decorator automatically skips tests if the target doesn't support required capabilities:\n\n```python\nfrom score.itf.plugins.core import requires_capabilities\n\n@requires_capabilities(\"exec\")\ndef test_docker_specific(target):\n    # Only runs on targets with 'exec' capability\n    target.execute(\"echo test\")\n\n@requires_capabilities(\"ssh\", \"sftp\")\ndef test_network_features(target):\n    # Only runs on targets with both 'ssh' and 'sftp'\n    with target.ssh() as ssh:\n        pass\n```\n\n## Communication APIs\n\n### SSH Operations\n\n```python\nfrom score.itf.core.com.ssh import execute_command\n\ndef test_ssh_command(target):\n    with target.ssh(username=\"root\", password=\"\") as ssh:\n        result = execute_command(ssh, \"ls -la /tmp\")\n```\n\n### SFTP File Transfer\n\n```python\ndef test_file_transfer(target):\n    with target.sftp() as sftp:\n        sftp.put(\"local_file.txt\", \"/tmp/remote_file.txt\")\n        sftp.get(\"/tmp/remote_file.txt\", \"downloaded_file.txt\")\n```\n\n### Network Testing\n\n```python\ndef test_ping(target):\n    # Check if target is reachable\n    assert target.ping(timeout=5)\n    \n    # Wait until target becomes unreachable\n    target.ping_lost(timeout=30, interval=1)\n```\n\n## DLT Support\n\nThe DLT plugin enables capturing and analyzing Diagnostic Log and Trace messages. `DltWindow` captures DLT messages from a target and allows querying the recorded data:\n\n```python\nfrom score.itf.plugins.dlt.dlt_window import DltWindow\nfrom score.itf.plugins.dlt.dlt_receive import Protocol\nimport re\n\ndef test_with_dlt_capture(target, dlt_config):\n    # Create DltWindow to capture DLT messages via UDP\n    with DltWindow(\n        protocol=Protocol.UDP,\n        host_ip=\"127.0.0.1\",\n        multicast_ips=[\"224.0.0.1\"],\n        print_to_stdout=False,\n        binary_path=dlt_config.dlt_receive_path,\n    ) as window:\n        # Perform operations that generate DLT messages\n        with target.ssh() as ssh:\n            execute_command(ssh, \"my_application\")\n        \n        # Access the recorded DLT data\n        record = window.record()\n        \n        # Query for specific DLT messages\n        query = {\n            \"apid\": re.compile(r\"APP1\"),\n            \"payload\": re.compile(r\".*Started successfully.*\")\n        }\n        results = record.find(query=query)\n        assert len(results) \u003e 0\n        \n        # Or iterate through all messages\n        for frame in record.find():\n            if \"error\" in frame.payload.lower():\n                print(f\"Error found: {frame.payload}\")\n```\n\nDLT messages can also be captured with TCP protocol and optional filters:\n\n```python\n# TCP connection to specific target\nwith DltWindow(\n    protocol=Protocol.TCP,\n    target_ip=\"192.168.1.100\",\n    print_to_stdout=True,\n    binary_path=dlt_config.dlt_receive_path,\n) as window:\n    # Operations...\n    pass\n\n# With application/context ID filter\nwith DltWindow(\n    protocol=Protocol.UDP,\n    host_ip=\"127.0.0.1\",\n    multicast_ips=[\"224.0.0.1\"],\n    dlt_filter=\"APPID CTID\",  # Filter by APPID and CTID\n    binary_path=dlt_config.dlt_receive_path,\n) as window:\n    # Operations...\n    pass\n```\n\n### DLT Configuration File\n\nDLT settings can be specified in a JSON configuration file:\n\n```json\n{\n    \"target_ip\": \"192.168.122.76\",\n    \"host_ip\": \"192.168.122.1\",\n    \"multicast_ips\": [\n        \"239.255.42.99\"\n    ]\n}\n```\n\nThis configuration file can be passed to tests via the `--dlt-config` argument in the BUILD file:\n\n```starlark\npy_itf_test(\n    name = \"test_with_dlt\",\n    srcs = [\"test.py\"],\n    args = [\n        \"--dlt-config=$(location dlt_config.json)\",\n    ],\n    data = [\"dlt_config.json\"],\n    plugins = [dlt, docker],\n)\n```\n\n## Advanced Features\n\n### Target Lifecycle Management\n\nControl whether targets persist across tests using the `--keep-target` flag:\n\n```bash\n# Keep target running between tests (faster, but shared state)\nbazel test //test:my_test -- --test_arg=\"--keep-target\"\n\n# Default: Create fresh target for each test\nbazel test //test:my_test\n```\n\n### Custom Docker Configuration\n\nOverride Docker settings in tests:\n\n```python\nimport pytest\n\n@pytest.fixture\ndef docker_configuration():\n    return {\n        \"environment\": {\"MY_VAR\": \"value\"},\n        \"command\": \"my-custom-command\",\n        \"ports\": {\"8080/tcp\": 8080},\n    }\n\ndef test_with_custom_docker(target):\n    # Uses custom configuration\n    pass\n```\n## Running Tests\n\n### Basic Test Execution\n\n```bash\n# Run all tests\nbazel test //test/...\n\n# Run specific test\nbazel test //test:test_docker\n\n# Show test output\nbazel test //test:test_docker --test_output=all\n\n# Show pytest output\nbazel test //test:test_docker --test_arg=\"-s\"\n\n# Don't cache test results\nbazel test //test:test_docker --nocache_test_results\n```\n\n### Docker Tests\n\n```bash\nbazel test //test:test_docker \\\n    --test_arg=\"--docker-image=ubuntu:24.04\"\n```\n\n### QEMU Tests\n\n```bash\n# With pre-built QEMU image\nbazel test //test:test_qemu \\\n    --test_arg=\"--qemu-image=/path/to/kernel.img\"\n```\n\n## QEMU Setup (Linux)\n\n### Prerequisites\n\nCheck KVM support:\n```bash\nls -l /dev/kvm\n```\n\nIf `/dev/kvm` exists, your system supports hardware virtualization.\n\n### Installation (Ubuntu/Debian)\n\n```bash\nsudo apt-get install qemu-kvm libvirt-daemon-system \\\n    libvirt-clients bridge-utils qemu-utils\n\n# Add user to required groups\nsudo adduser $(id -un) libvirt\nsudo adduser $(id -un) kvm\n\n# Re-login to apply group changes\nsudo login $(id -un)\n\n# Verify group membership\ngroups\n```\n\n### KVM Acceleration\n\nITF automatically detects KVM availability and uses:\n- **KVM acceleration** when `/dev/kvm` is accessible (fast)\n- **TCG emulation** as fallback (slower, no virtualization)\n\n## Development\n\n### Regenerating Dependencies\n\n```bash\nbazel run //:requirements.update\n```\n\n### Code Formatting\n\n```bash\nbazel run //:format.fix\n```\n\n### Running Tests During Development\n\n```bash\n# Run with verbose output\nbazel test //test/... \\\n    --test_output=all \\\n    --test_arg=\"-s\" \\\n    --nocache_test_results\n```\n\n## Creating Custom Plugins\n\nCreate a custom plugin by implementing the pytest hooks:\n\n```python\n# my_plugin.py\nimport pytest\nfrom score.itf.plugins.core import Target, determine_target_scope\n\nMY_CAPABILITIES = [\"custom_feature\"]\n\nclass MyTarget(Target):\n    def __init__(self):\n        super().__init__(capabilities=MY_CAPABILITIES)\n    \n    def custom_operation(self):\n        # Custom functionality\n        pass\n\n@pytest.fixture(scope=determine_target_scope)\ndef target_init():\n    yield MyTarget()\n```\n\nRegister the plugin in `plugins.bzl`:\n\n```starlark\nload(\"//bazel:py_itf_plugin.bzl\", \"py_itf_plugin\")\n\nmy_plugin = py_itf_plugin(\n    py_library = \"//path/to:my_plugin\",\n    enabled_plugins = [\"my_plugin\"],\n    args = [],\n    data = [],\n    data_as_exec = [],\n    tags = [],\n)\n```\n\nUse in tests:\n\n```starlark\npy_itf_test(\n    name = \"test_custom\",\n    srcs = [\"test.py\"],\n    plugins = [my_plugin],\n)\n```\n\n## Project Structure\n\n```\nscore/itf/\n├── core/                 # Core ITF functionality\n│   ├── com/              # Communication modules (SSH, SFTP)\n│   ├── process/          # Process management\n│   ├── target/           # Target base class\n│   └── utils/            # Utility functions\n├── plugins/              # Plugin implementations\n│   ├── core.py           # Core plugin with Target and decorators\n│   ├── docker.py         # Docker plugin\n│   ├── dlt/              # DLT plugin\n│   └── qemu/             # QEMU plugin\n└── ...\n```\n\n## Contributing\n\nContributions are welcome! Please ensure:\n- All tests pass: `bazel test //test/...`\n- Code is formatted: `bazel run //:format.fix`\n- New features include tests and documentation\n\n## License\n\nApache License 2.0 - See [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclipse-score%2Fitf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feclipse-score%2Fitf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclipse-score%2Fitf/lists"}