rosotacom-dev 2.5.dev5__tar.gz → 2.5.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/PKG-INFO +23 -1
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/README.md +22 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/testing.md +10 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/cli.py +231 -30
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/status_eval.py +21 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/PKG-INFO +23 -1
- rosotacom_dev-2.5.dev7/src/rosotacom_dev.egg-info/scm_version.json +8 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_cli.py +128 -1
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_status_eval.py +27 -0
- rosotacom_dev-2.5.dev5/src/rosotacom_dev.egg-info/scm_version.json +0 -8
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/install.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/justfile +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/run_session_in_container.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/stop_session_in_container.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev5 → rosotacom_dev-2.5.dev7}/tests/unit/test_video_quality.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev7
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -460,6 +460,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
|
460
460
|
--install-mode pin # defaults to your own version
|
|
461
461
|
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
462
462
|
--install-mode pin --install-pin 2.4
|
|
463
|
+
|
|
464
|
+
# test the machines as they are: no staging, no install, their own checkouts
|
|
465
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
466
|
+
--peer-ssh b=robot-b --install-mode checkout \
|
|
467
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
|
|
463
468
|
```
|
|
464
469
|
|
|
465
470
|
`source` is right while iterating on rosotacom itself — the peers run the code
|
|
@@ -469,6 +474,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
|
|
|
469
474
|
of on the target machine. `source` cannot catch that class of defect by
|
|
470
475
|
construction, because it never builds the artefact that ships.
|
|
471
476
|
|
|
477
|
+
`checkout` answers a different question again: not "does this artefact work" but
|
|
478
|
+
"is *this machine* ready". Nothing is staged and nothing is installed — each
|
|
479
|
+
peer runs the rosotacom it already has, from the project checkout it already
|
|
480
|
+
has, so what is under test is the state git and the machine's own install left
|
|
481
|
+
behind, dependency pins included. Ground truth moves into the repository: push,
|
|
482
|
+
pull, run. It is also the only mode in which a project may reference anything
|
|
483
|
+
outside its own directory — staging copies the project directory, so a mount or
|
|
484
|
+
config path leading above it cannot survive the copy and fails on the peer as a
|
|
485
|
+
missing path.
|
|
486
|
+
|
|
487
|
+
Because the same repository sits at a different absolute path on every machine,
|
|
488
|
+
`--peer-checkout` is required for every peer; the path *inside* the repository
|
|
489
|
+
is taken from your own checkout, so the project has to live in one. Preparation
|
|
490
|
+
becomes verification: each peer is asked whether the checkout, the project file
|
|
491
|
+
and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
|
|
492
|
+
in this mode — there is no staging to undo, and the workdir is your repository.
|
|
493
|
+
|
|
472
494
|
The run manifest records which mode and which version the peers ran, so a result
|
|
473
495
|
can be attributed to an artefact rather than to a working copy.
|
|
474
496
|
|
|
@@ -415,6 +415,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
|
415
415
|
--install-mode pin # defaults to your own version
|
|
416
416
|
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
417
417
|
--install-mode pin --install-pin 2.4
|
|
418
|
+
|
|
419
|
+
# test the machines as they are: no staging, no install, their own checkouts
|
|
420
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
421
|
+
--peer-ssh b=robot-b --install-mode checkout \
|
|
422
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
|
|
418
423
|
```
|
|
419
424
|
|
|
420
425
|
`source` is right while iterating on rosotacom itself — the peers run the code
|
|
@@ -424,6 +429,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
|
|
|
424
429
|
of on the target machine. `source` cannot catch that class of defect by
|
|
425
430
|
construction, because it never builds the artefact that ships.
|
|
426
431
|
|
|
432
|
+
`checkout` answers a different question again: not "does this artefact work" but
|
|
433
|
+
"is *this machine* ready". Nothing is staged and nothing is installed — each
|
|
434
|
+
peer runs the rosotacom it already has, from the project checkout it already
|
|
435
|
+
has, so what is under test is the state git and the machine's own install left
|
|
436
|
+
behind, dependency pins included. Ground truth moves into the repository: push,
|
|
437
|
+
pull, run. It is also the only mode in which a project may reference anything
|
|
438
|
+
outside its own directory — staging copies the project directory, so a mount or
|
|
439
|
+
config path leading above it cannot survive the copy and fails on the peer as a
|
|
440
|
+
missing path.
|
|
441
|
+
|
|
442
|
+
Because the same repository sits at a different absolute path on every machine,
|
|
443
|
+
`--peer-checkout` is required for every peer; the path *inside* the repository
|
|
444
|
+
is taken from your own checkout, so the project has to live in one. Preparation
|
|
445
|
+
becomes verification: each peer is asked whether the checkout, the project file
|
|
446
|
+
and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
|
|
447
|
+
in this mode — there is no staging to undo, and the workdir is your repository.
|
|
448
|
+
|
|
427
449
|
The run manifest records which mode and which version the peers ran, so a result
|
|
428
450
|
can be attributed to an artefact rather than to a working copy.
|
|
429
451
|
|
|
@@ -75,6 +75,16 @@ planned decimation is not counted as OTA loss. The default `--min-ratio 0.9`
|
|
|
75
75
|
leaves a safety margin for a healthy link; tune it per gate instead of
|
|
76
76
|
committing a brittle 100% threshold.
|
|
77
77
|
|
|
78
|
+
**`vs_bag_ratio` is replay-only, and the run refuses to pretend otherwise.** It
|
|
79
|
+
compares the delivered rate to the source's native rate, which only the bag
|
|
80
|
+
knows, so `rosotacom test` needs `--bag <dir>` to evaluate it. Until #214 a run
|
|
81
|
+
without one skipped those assertions silently and still printed `TEST OK` — a
|
|
82
|
+
session could declare completeness on every topic and have none of it checked.
|
|
83
|
+
`test` now exits non-zero naming the topics instead. If a session genuinely is
|
|
84
|
+
not replay-driven, drop the assertion rather than running without the bag: a
|
|
85
|
+
skipped check reads as coverage, which is the failure mode these contracts
|
|
86
|
+
exist to catch.
|
|
87
|
+
|
|
78
88
|
Transient-local or explicitly latched topics become `mode: latched`, because the
|
|
79
89
|
contract is that the held value arrives, not that the topic keeps ticking.
|
|
80
90
|
Sparse volatile topics become `mode: existence`; the current expect model has no
|
|
@@ -125,9 +125,25 @@ OTA_SUDO_MODES = ("passwordless", "askpass")
|
|
|
125
125
|
# that ships, so a packaging defect — a file missing from the wheel, an
|
|
126
126
|
# undeclared dependency — fails here rather than on a Versuchsträger. `source`
|
|
127
127
|
# cannot catch that class of bug by construction.
|
|
128
|
-
|
|
128
|
+
#
|
|
129
|
+
# `checkout` is the third answer, and it inverts the question: nothing is
|
|
130
|
+
# staged and nothing is installed. Each peer runs the rosotacom it already has
|
|
131
|
+
# from the project checkout it already has, so what is under test is the state
|
|
132
|
+
# git put on that machine — including its dependency pins. `pin` still proves
|
|
133
|
+
# the artefact ships correctly; only `checkout` proves *this machine* is ready,
|
|
134
|
+
# which is what a deployment rehearsal actually asks. It is also the only mode
|
|
135
|
+
# in which a project may reference anything outside its own directory: staging
|
|
136
|
+
# copies the project directory, so a path leading above it cannot survive.
|
|
137
|
+
OTA_INSTALL_MODES = ("source", "pin", "checkout")
|
|
129
138
|
OTA_DEFAULT_SUDO_MODE = "passwordless"
|
|
130
139
|
|
|
140
|
+
# `ssh host 'cmd'` runs a non-login shell, so a pipx install in ~/.local/bin is
|
|
141
|
+
# not on PATH and the peer answers `rosotacom: command not found` — which reads
|
|
142
|
+
# as a broken machine rather than a missing PATH entry. The staged modes never
|
|
143
|
+
# meet this because they call an absolute path inside the workdir; checkout mode
|
|
144
|
+
# calls the peer's own command by name, so it has to say where that lives.
|
|
145
|
+
OTA_CHECKOUT_PATH_PREFIX = 'export PATH="$HOME/.local/bin:$PATH"; '
|
|
146
|
+
|
|
131
147
|
ws_creation_dir = WS_DIR / "session" / "creation"
|
|
132
148
|
session_gen_path = ws_creation_dir / "generate_session_files.py"
|
|
133
149
|
spec = importlib.util.spec_from_file_location("session_gen", session_gen_path)
|
|
@@ -212,6 +228,12 @@ class OtaSmokePeer:
|
|
|
212
228
|
name: str
|
|
213
229
|
ssh: str | None
|
|
214
230
|
address: str
|
|
231
|
+
#: Absolute path of this peer's project checkout, in `checkout` install mode
|
|
232
|
+
#: only. Per peer rather than one plan-wide value because the same
|
|
233
|
+
#: repository lives at a different absolute path on every machine — a
|
|
234
|
+
#: control centre runs it under a different account than a laptop does — and
|
|
235
|
+
#: a single workdir would silently be wrong on all but one of them.
|
|
236
|
+
checkout: str | None = None
|
|
215
237
|
|
|
216
238
|
|
|
217
239
|
@dataclass(frozen=True)
|
|
@@ -1001,6 +1023,10 @@ def _parse_peer_ssh_overrides(overrides: list[str] | None) -> dict[str, str]:
|
|
|
1001
1023
|
return parse_assignments(overrides, option="--peer-ssh")
|
|
1002
1024
|
|
|
1003
1025
|
|
|
1026
|
+
def _parse_peer_checkout_overrides(overrides: list[str] | None) -> dict[str, str]:
|
|
1027
|
+
return parse_assignments(overrides, option="--peer-checkout")
|
|
1028
|
+
|
|
1029
|
+
|
|
1004
1030
|
def _deployment_config(runtime: RuntimeConfig) -> DeploymentConfig | None:
|
|
1005
1031
|
return load_deployment(runtime.deployment)
|
|
1006
1032
|
|
|
@@ -1500,18 +1526,65 @@ def _ota_validate_install_mode(install_mode: str) -> str:
|
|
|
1500
1526
|
|
|
1501
1527
|
def _ota_rosotacom_path(install_mode: str) -> str:
|
|
1502
1528
|
"""Where the peer's rosotacom executable lands, relative to the workdir."""
|
|
1529
|
+
if install_mode == "checkout":
|
|
1530
|
+
# Not a path: the peer's own installation, whatever put it there. Naming
|
|
1531
|
+
# a path here would re-introduce the thing this mode removes — an
|
|
1532
|
+
# assumption by the orchestrator about the peer's file system.
|
|
1533
|
+
return "rosotacom"
|
|
1503
1534
|
return "venv/bin/rosotacom" if install_mode == "pin" else "source/.venv/bin/rosotacom"
|
|
1504
1535
|
|
|
1505
1536
|
|
|
1537
|
+
def _ota_checkout_project_path(project_config: Path) -> tuple[Path, str]:
|
|
1538
|
+
"""Split an active `rosotacom.yaml` into (checkout root, path inside it).
|
|
1539
|
+
|
|
1540
|
+
Checkout mode needs one repository-relative project path that is valid on
|
|
1541
|
+
every peer, and the honest source for it is the local checkout: walk up from
|
|
1542
|
+
the config until a `.git` entry appears. That is not a heuristic here — a
|
|
1543
|
+
mode whose ground truth is "what git put on the machine" is entitled to
|
|
1544
|
+
require that the project is in a repository, and requiring it makes the
|
|
1545
|
+
failure legible instead of producing a path that happens to be wrong on the
|
|
1546
|
+
other machine.
|
|
1547
|
+
"""
|
|
1548
|
+
config = project_config.resolve()
|
|
1549
|
+
for candidate in config.parents:
|
|
1550
|
+
if (candidate / ".git").exists():
|
|
1551
|
+
return candidate, config.relative_to(candidate).as_posix()
|
|
1552
|
+
raise RuntimeError(
|
|
1553
|
+
f"--install-mode checkout needs the project to live in a git checkout, and {config} is not in one. "
|
|
1554
|
+
"The peers resolve the project by its path inside the repository, so there has to be a repository."
|
|
1555
|
+
)
|
|
1556
|
+
|
|
1557
|
+
|
|
1506
1558
|
def _ota_plan_from_bindings(
|
|
1507
1559
|
bindings: dict[str, PeerBinding],
|
|
1508
1560
|
*,
|
|
1509
1561
|
workdir: str,
|
|
1510
1562
|
install_mode: str = "source",
|
|
1511
1563
|
install_pin: str | None = None,
|
|
1564
|
+
checkouts: Mapping[str, str] | None = None,
|
|
1565
|
+
project: str | None = None,
|
|
1512
1566
|
) -> OtaSmokePlan:
|
|
1513
|
-
_ota_validate_prepare_workdir(workdir)
|
|
1514
1567
|
_ota_validate_install_mode(install_mode)
|
|
1568
|
+
if install_mode == "checkout":
|
|
1569
|
+
if not checkouts or not project:
|
|
1570
|
+
raise RuntimeError("--install-mode checkout requires --peer-checkout for every peer.")
|
|
1571
|
+
missing = sorted(set(bindings) - set(checkouts))
|
|
1572
|
+
if missing:
|
|
1573
|
+
raise RuntimeError(
|
|
1574
|
+
"--install-mode checkout needs a checkout for every peer; missing: "
|
|
1575
|
+
+ ", ".join(f"--peer-checkout {name}=<path>" for name in missing)
|
|
1576
|
+
)
|
|
1577
|
+
unknown = sorted(set(checkouts) - set(bindings))
|
|
1578
|
+
if unknown:
|
|
1579
|
+
raise RuntimeError(f"--peer-checkout names a peer the session does not have: {', '.join(unknown)}")
|
|
1580
|
+
for name, path in sorted(checkouts.items()):
|
|
1581
|
+
if not path.startswith("/"):
|
|
1582
|
+
raise RuntimeError(f"--peer-checkout {name}={path}: a peer checkout must be an absolute path.")
|
|
1583
|
+
_ota_validate_prepare_workdir(path)
|
|
1584
|
+
else:
|
|
1585
|
+
_ota_validate_prepare_workdir(workdir)
|
|
1586
|
+
if checkouts:
|
|
1587
|
+
raise RuntimeError("--peer-checkout only applies to --install-mode checkout.")
|
|
1515
1588
|
if install_mode == "pin":
|
|
1516
1589
|
# Defaulting to the caller's own version makes `--install-mode pin`
|
|
1517
1590
|
# mean "rehearse what I am running, as it ships" without a second flag.
|
|
@@ -1524,13 +1597,19 @@ def _ota_plan_from_bindings(
|
|
|
1524
1597
|
elif install_pin is not None:
|
|
1525
1598
|
raise RuntimeError("--install-pin only applies to --install-mode pin.")
|
|
1526
1599
|
peers = {
|
|
1527
|
-
name: OtaSmokePeer(
|
|
1600
|
+
name: OtaSmokePeer(
|
|
1601
|
+
name=name,
|
|
1602
|
+
ssh=binding.ssh,
|
|
1603
|
+
address=binding.address,
|
|
1604
|
+
checkout=(checkouts or {}).get(name) if install_mode == "checkout" else None,
|
|
1605
|
+
)
|
|
1606
|
+
for name, binding in bindings.items()
|
|
1528
1607
|
}
|
|
1529
1608
|
return OtaSmokePlan(
|
|
1530
1609
|
state_path=None,
|
|
1531
1610
|
workdir=workdir,
|
|
1532
1611
|
rosotacom=_ota_rosotacom_path(install_mode),
|
|
1533
|
-
project="project/rosotacom.yaml",
|
|
1612
|
+
project=(project or "") if install_mode == "checkout" else "project/rosotacom.yaml",
|
|
1534
1613
|
peers=peers,
|
|
1535
1614
|
install_mode=install_mode,
|
|
1536
1615
|
install_pin=install_pin,
|
|
@@ -1540,13 +1619,16 @@ def _ota_plan_from_bindings(
|
|
|
1540
1619
|
def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokePlan:
|
|
1541
1620
|
path = instance.host_dir / "ota-deployment.yaml"
|
|
1542
1621
|
payload = {
|
|
1543
|
-
"schema_version":
|
|
1622
|
+
"schema_version": 3,
|
|
1544
1623
|
"workdir": plan.workdir,
|
|
1545
1624
|
"rosotacom": plan.rosotacom,
|
|
1546
1625
|
"project": plan.project,
|
|
1547
1626
|
"install_mode": plan.install_mode,
|
|
1548
1627
|
"install_pin": plan.install_pin,
|
|
1549
|
-
"peers": {
|
|
1628
|
+
"peers": {
|
|
1629
|
+
name: {"address": peer.address, "ssh": peer.ssh, "checkout": peer.checkout}
|
|
1630
|
+
for name, peer in sorted(plan.peers.items())
|
|
1631
|
+
},
|
|
1550
1632
|
}
|
|
1551
1633
|
path.write_text(yaml.safe_dump(payload, sort_keys=False), encoding="utf-8")
|
|
1552
1634
|
return replace(plan, state_path=path)
|
|
@@ -1555,7 +1637,7 @@ def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokeP
|
|
|
1555
1637
|
def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
1556
1638
|
path = Path(path_arg).expanduser().resolve()
|
|
1557
1639
|
raw = _load_yaml_file(path)
|
|
1558
|
-
if raw.get("schema_version") !=
|
|
1640
|
+
if raw.get("schema_version") != 3:
|
|
1559
1641
|
raise RuntimeError(f"Unsupported OTA deployment state: {path}")
|
|
1560
1642
|
peers_raw = raw.get("peers")
|
|
1561
1643
|
if not isinstance(peers_raw, dict) or len(peers_raw) != 2:
|
|
@@ -1568,6 +1650,7 @@ def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
|
1568
1650
|
name=str(name),
|
|
1569
1651
|
address=str(peer_raw["address"]),
|
|
1570
1652
|
ssh=str(peer_raw["ssh"]) if peer_raw.get("ssh") else None,
|
|
1653
|
+
checkout=str(peer_raw["checkout"]) if peer_raw.get("checkout") else None,
|
|
1571
1654
|
)
|
|
1572
1655
|
install_pin = raw.get("install_pin")
|
|
1573
1656
|
return OtaSmokePlan(
|
|
@@ -1680,9 +1763,15 @@ def _ota_project_cli_args(plan: OtaSmokePlan) -> list[str]:
|
|
|
1680
1763
|
return ["--rosotacom-config", plan.project]
|
|
1681
1764
|
|
|
1682
1765
|
|
|
1683
|
-
def
|
|
1766
|
+
def _ota_peer_workdir(plan: OtaSmokePlan, peer: OtaSmokePeer) -> str:
|
|
1767
|
+
"""The directory a peer's commands run in: its checkout, or the staging dir."""
|
|
1768
|
+
return peer.checkout or plan.workdir
|
|
1769
|
+
|
|
1770
|
+
|
|
1771
|
+
def _ota_rosotacom_command(plan: OtaSmokePlan, parts: list[str], peer: OtaSmokePeer) -> str:
|
|
1684
1772
|
command = [plan.rosotacom, *parts, *_ota_project_cli_args(plan)]
|
|
1685
|
-
|
|
1773
|
+
prefix = OTA_CHECKOUT_PATH_PREFIX if plan.install_mode == "checkout" else ""
|
|
1774
|
+
return f"{prefix}cd {shlex.quote(_ota_peer_workdir(plan, peer))} && {_ota_quote_cmd(command)}"
|
|
1686
1775
|
|
|
1687
1776
|
|
|
1688
1777
|
def _ota_source_checkout() -> Path | None:
|
|
@@ -2248,11 +2337,27 @@ def _resolve_ota_smoke_context(
|
|
|
2248
2337
|
peer_address=getattr(args, "peer_address", None),
|
|
2249
2338
|
peer_ssh=getattr(args, "peer_ssh", None),
|
|
2250
2339
|
)
|
|
2340
|
+
install_mode = str(getattr(args, "install_mode", None) or "source")
|
|
2341
|
+
checkouts = _parse_peer_checkout_overrides(getattr(args, "peer_checkout", None))
|
|
2342
|
+
project: str | None = None
|
|
2343
|
+
if install_mode == "checkout":
|
|
2344
|
+
if not runtime.rosotacom_config:
|
|
2345
|
+
raise RuntimeError("--install-mode checkout requires an active rosotacom.yaml project.")
|
|
2346
|
+
local_checkout, project = _ota_checkout_project_path(runtime.rosotacom_config)
|
|
2347
|
+
for name, path in sorted(checkouts.items()):
|
|
2348
|
+
binding = bindings.get(name)
|
|
2349
|
+
if binding is not None and not binding.ssh and Path(path).resolve() != local_checkout:
|
|
2350
|
+
raise RuntimeError(
|
|
2351
|
+
f"--peer-checkout {name}={path} names the peer that runs on this machine, but the active "
|
|
2352
|
+
f"project lives in {local_checkout}. Point it there, or give that peer an SSH target."
|
|
2353
|
+
)
|
|
2251
2354
|
plan = _ota_plan_from_bindings(
|
|
2252
2355
|
bindings,
|
|
2253
2356
|
workdir=str(getattr(args, "workdir", None) or "/tmp/rosotacom_ota"),
|
|
2254
|
-
install_mode=
|
|
2357
|
+
install_mode=install_mode,
|
|
2255
2358
|
install_pin=getattr(args, "install_pin", None),
|
|
2359
|
+
checkouts=checkouts,
|
|
2360
|
+
project=project,
|
|
2256
2361
|
)
|
|
2257
2362
|
plan_peers = set(plan.peers)
|
|
2258
2363
|
target_peers = set(_peer_keys_from_cfg(target.cfg))
|
|
@@ -2643,10 +2748,62 @@ def _ota_remote_package_dir(peer: OtaSmokePeer, plan: OtaSmokePlan, *, dry_run:
|
|
|
2643
2748
|
return located
|
|
2644
2749
|
|
|
2645
2750
|
|
|
2751
|
+
def _ota_verify_checkouts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
|
|
2752
|
+
"""Checkout mode's replacement for staging: assert, do not install.
|
|
2753
|
+
|
|
2754
|
+
Nothing is copied and nothing is installed, so the only thing that can go
|
|
2755
|
+
wrong is a peer that is not in the state the caller thinks it is in — an
|
|
2756
|
+
unsynced checkout, a rosotacom that never got installed, a project path that
|
|
2757
|
+
exists on the laptop and not on the other machine. Each of those has a
|
|
2758
|
+
distinct one-line failure here, before any container starts, rather than a
|
|
2759
|
+
confusing one an hour later.
|
|
2760
|
+
"""
|
|
2761
|
+
for peer in plan.peers.values():
|
|
2762
|
+
checkout = shlex.quote(_ota_peer_workdir(plan, peer))
|
|
2763
|
+
project = shlex.quote(plan.project)
|
|
2764
|
+
_ota_run(
|
|
2765
|
+
peer,
|
|
2766
|
+
f"test -d {checkout}",
|
|
2767
|
+
label=f"{peer.name}: project checkout {_ota_peer_workdir(plan, peer)}",
|
|
2768
|
+
dry_run=dry_run,
|
|
2769
|
+
batch=True,
|
|
2770
|
+
)
|
|
2771
|
+
_ota_run(
|
|
2772
|
+
peer,
|
|
2773
|
+
f"test -f {checkout}/{project}",
|
|
2774
|
+
label=f"{peer.name}: project config {plan.project} inside the checkout",
|
|
2775
|
+
dry_run=dry_run,
|
|
2776
|
+
batch=True,
|
|
2777
|
+
)
|
|
2778
|
+
_ota_run(
|
|
2779
|
+
peer,
|
|
2780
|
+
f"{OTA_CHECKOUT_PATH_PREFIX}command -v rosotacom >/dev/null 2>&1",
|
|
2781
|
+
label=f"{peer.name}: rosotacom installed",
|
|
2782
|
+
dry_run=dry_run,
|
|
2783
|
+
batch=True,
|
|
2784
|
+
)
|
|
2785
|
+
version = _ota_run(
|
|
2786
|
+
peer,
|
|
2787
|
+
f"{OTA_CHECKOUT_PATH_PREFIX}rosotacom --version",
|
|
2788
|
+
label=f"{peer.name}: rosotacom version",
|
|
2789
|
+
dry_run=dry_run,
|
|
2790
|
+
batch=True,
|
|
2791
|
+
check=False,
|
|
2792
|
+
)
|
|
2793
|
+
if not dry_run and version.returncode == 0:
|
|
2794
|
+
# Printed rather than enforced. Peers running different versions is
|
|
2795
|
+
# a real hazard, but it is also a legitimate mid-migration state,
|
|
2796
|
+
# and a check that refuses it would be the wrong place to find out.
|
|
2797
|
+
print(f"+ {peer.name}: rosotacom {version.stdout.strip() or 'unknown'}")
|
|
2798
|
+
|
|
2799
|
+
|
|
2646
2800
|
def _ota_prepare_hosts(args: argparse.Namespace, runtime: RuntimeConfig, plan: OtaSmokePlan) -> None:
|
|
2647
2801
|
if not runtime.rosotacom_config:
|
|
2648
2802
|
raise RuntimeError("ota-smoke requires an active rosotacom.yaml project.")
|
|
2649
2803
|
dry_run = bool(getattr(args, "dry_run", False))
|
|
2804
|
+
if plan.install_mode == "checkout":
|
|
2805
|
+
_ota_verify_checkouts(plan, dry_run=dry_run)
|
|
2806
|
+
return
|
|
2650
2807
|
from_pin = plan.install_mode == "pin"
|
|
2651
2808
|
source_checkout: Path | None = None
|
|
2652
2809
|
temporary_bundle: Path | None = None
|
|
@@ -2924,6 +3081,7 @@ def _ota_start_peers(
|
|
|
2924
3081
|
command = _ota_rosotacom_command(
|
|
2925
3082
|
plan,
|
|
2926
3083
|
_ota_start_parts(target, peer_name, instance_id, peer_args, mode=mode, link_trace_parts=link_trace_parts),
|
|
3084
|
+
peer,
|
|
2927
3085
|
)
|
|
2928
3086
|
_ota_run(peer, command, label=f"{peer_name}: start {target.name}", dry_run=dry_run)
|
|
2929
3087
|
|
|
@@ -2940,7 +3098,7 @@ def _ota_start_session_publishers(
|
|
|
2940
3098
|
peer_args = _ota_peer_address_args(plan)
|
|
2941
3099
|
for peer_name in sorted(plan.peers):
|
|
2942
3100
|
peer = plan.peers[peer_name]
|
|
2943
|
-
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args))
|
|
3101
|
+
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args), peer)
|
|
2944
3102
|
result = _ota_run(peer, command, label=f"{peer_name}: start synthetic publishers", dry_run=dry_run, check=False)
|
|
2945
3103
|
_print_completed_output(result)
|
|
2946
3104
|
if result.returncode != 0:
|
|
@@ -2958,7 +3116,7 @@ def _ota_stop_session_publishers(
|
|
|
2958
3116
|
peer_args = _ota_peer_address_args(plan)
|
|
2959
3117
|
for peer_name in sorted(plan.peers):
|
|
2960
3118
|
peer = plan.peers[peer_name]
|
|
2961
|
-
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, stop=True))
|
|
3119
|
+
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, stop=True), peer)
|
|
2962
3120
|
_ota_run(peer, command, label=f"{peer_name}: stop synthetic publishers", dry_run=dry_run, check=False)
|
|
2963
3121
|
|
|
2964
3122
|
|
|
@@ -2974,7 +3132,7 @@ def _ota_verify_delivery(
|
|
|
2974
3132
|
print("OTA smoke: running status/expectation checks on every peer.")
|
|
2975
3133
|
for peer_name in sorted(plan.peers):
|
|
2976
3134
|
peer = plan.peers[peer_name]
|
|
2977
|
-
command = _ota_rosotacom_command(plan, _ota_test_parts(target, instance_id, profile=profile))
|
|
3135
|
+
command = _ota_rosotacom_command(plan, _ota_test_parts(target, instance_id, profile=profile), peer)
|
|
2978
3136
|
result = _ota_run(peer, command, label=f"{peer_name}: rosotacom test", dry_run=dry_run, check=False)
|
|
2979
3137
|
if result.returncode != 0:
|
|
2980
3138
|
_ota_print_failure_output(f"{peer_name}: rosotacom test", result)
|
|
@@ -2997,14 +3155,14 @@ def _ota_verify_isolation(
|
|
|
2997
3155
|
peer_args = _ota_peer_address_args(plan)
|
|
2998
3156
|
errors: list[str] = []
|
|
2999
3157
|
print(f"OTA smoke: checking isolation from {source_name} to {receiver_name}.")
|
|
3000
|
-
publish = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=False))
|
|
3158
|
+
publish = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=False), source)
|
|
3001
3159
|
published = _ota_run(source, publish, label=f"{source_name}: publish isolation probe", dry_run=dry_run, check=False)
|
|
3002
3160
|
if published.returncode != 0:
|
|
3003
3161
|
_ota_print_failure_output(f"{source_name}: publish isolation probe", published)
|
|
3004
3162
|
errors.append(f"{source_name}: isolation probe publisher failed")
|
|
3005
3163
|
return errors
|
|
3006
3164
|
_print_completed_output(published)
|
|
3007
|
-
check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args))
|
|
3165
|
+
check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args), receiver)
|
|
3008
3166
|
checked = _ota_run(
|
|
3009
3167
|
receiver,
|
|
3010
3168
|
check,
|
|
@@ -3017,7 +3175,7 @@ def _ota_verify_isolation(
|
|
|
3017
3175
|
errors.append(f"{receiver_name}: isolation probe crossed OTA boundary")
|
|
3018
3176
|
else:
|
|
3019
3177
|
_print_completed_output(checked)
|
|
3020
|
-
stop = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=True))
|
|
3178
|
+
stop = _ota_rosotacom_command(plan, _ota_probe_publish_parts(target, source_name, peer_args, stop=True), source)
|
|
3021
3179
|
stopped = _ota_run(source, stop, label=f"{source_name}: stop isolation probe", dry_run=dry_run, check=False)
|
|
3022
3180
|
_print_completed_output(stopped)
|
|
3023
3181
|
return errors
|
|
@@ -3046,7 +3204,7 @@ def _ota_verify_content_integrity(
|
|
|
3046
3204
|
for receiver_name, receiver in plan.peers.items():
|
|
3047
3205
|
for topic, msg_type, field, expected in _content_integrity_specs(cfg, receiver_name):
|
|
3048
3206
|
parts = _ota_content_check_parts(target, receiver_name, peer_args, topic, msg_type, field, expected)
|
|
3049
|
-
cmd = _ota_rosotacom_command(plan, parts)
|
|
3207
|
+
cmd = _ota_rosotacom_command(plan, parts, receiver)
|
|
3050
3208
|
print(f"OTA smoke: checking content integrity for {receiver_name} {topic}.")
|
|
3051
3209
|
result = _ota_run(
|
|
3052
3210
|
receiver, cmd, label=f"{receiver_name}: content integrity {topic}", dry_run=dry_run, check=False
|
|
@@ -3067,16 +3225,16 @@ def _ota_collect_logs(
|
|
|
3067
3225
|
) -> None:
|
|
3068
3226
|
project = shlex.quote(plan.project)
|
|
3069
3227
|
instance_suffix = shlex.quote(f"*_{instance.instance_id}")
|
|
3070
|
-
script = (
|
|
3071
|
-
f"cd {shlex.quote(plan.workdir)} && "
|
|
3072
|
-
f"project_dir=$(dirname {project}) && "
|
|
3073
|
-
f'instance_dir=$(find "$project_dir/session-instances" -mindepth 2 -maxdepth 2 '
|
|
3074
|
-
f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
|
|
3075
|
-
'if [ -n "$instance_dir" ]; then '
|
|
3076
|
-
'relative=${instance_dir#"$project_dir"/}; '
|
|
3077
|
-
'tar cz -C "$project_dir" "$relative" 2>/dev/null | base64; fi'
|
|
3078
|
-
)
|
|
3079
3228
|
for peer in plan.peers.values():
|
|
3229
|
+
script = (
|
|
3230
|
+
f"cd {shlex.quote(_ota_peer_workdir(plan, peer))} && "
|
|
3231
|
+
f"project_dir=$(dirname {project}) && "
|
|
3232
|
+
f'instance_dir=$(find "$project_dir/session-instances" -mindepth 2 -maxdepth 2 '
|
|
3233
|
+
f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
|
|
3234
|
+
'if [ -n "$instance_dir" ]; then '
|
|
3235
|
+
'relative=${instance_dir#"$project_dir"/}; '
|
|
3236
|
+
'tar cz -C "$project_dir" "$relative" 2>/dev/null | base64; fi'
|
|
3237
|
+
)
|
|
3080
3238
|
result = _ota_run(peer, script, label=f"{peer.name}: collect session-instances", dry_run=dry_run, check=False)
|
|
3081
3239
|
if dry_run or not result.stdout.strip():
|
|
3082
3240
|
continue
|
|
@@ -3139,7 +3297,7 @@ def _ota_stop_peers(
|
|
|
3139
3297
|
peer_args = _ota_peer_address_args(plan)
|
|
3140
3298
|
for peer_name in sorted(plan.peers):
|
|
3141
3299
|
peer = plan.peers[peer_name]
|
|
3142
|
-
command = _ota_rosotacom_command(plan, _ota_stop_parts(target, peer_name, instance_id, peer_args))
|
|
3300
|
+
command = _ota_rosotacom_command(plan, _ota_stop_parts(target, peer_name, instance_id, peer_args), peer)
|
|
3143
3301
|
_ota_run(peer, command, label=f"{peer_name}: stop {target.name}", dry_run=dry_run, check=False)
|
|
3144
3302
|
|
|
3145
3303
|
|
|
@@ -3186,7 +3344,9 @@ def _ota_application_run_script(
|
|
|
3186
3344
|
) -> str:
|
|
3187
3345
|
communication_suffix = _sanitize_docker_name(f"_com_to_{_remote_peer_name(target.cfg, peer_name)}")
|
|
3188
3346
|
label = f"{peer_name}:{application.name}"
|
|
3189
|
-
command = _ota_rosotacom_command(
|
|
3347
|
+
command = _ota_rosotacom_command(
|
|
3348
|
+
plan, _ota_application_parts(target, peer_name, application, instance_id), plan.peers[peer_name]
|
|
3349
|
+
)
|
|
3190
3350
|
return (
|
|
3191
3351
|
f"{_ota_wait_for_running_container_suffix_script(communication_suffix, f'{peer_name}:communication')}; "
|
|
3192
3352
|
f"echo '[INFO] starting native application container:' {shlex.quote(label)}; "
|
|
@@ -3219,6 +3379,7 @@ def _ota_create_tmux(
|
|
|
3219
3379
|
mode="attach",
|
|
3220
3380
|
link_trace_parts=link_trace_parts,
|
|
3221
3381
|
),
|
|
3382
|
+
first_peer,
|
|
3222
3383
|
)
|
|
3223
3384
|
first_script = (
|
|
3224
3385
|
"set -e; "
|
|
@@ -3298,6 +3459,7 @@ def _ota_create_tmux(
|
|
|
3298
3459
|
mode="attach",
|
|
3299
3460
|
link_trace_parts=link_trace_parts,
|
|
3300
3461
|
),
|
|
3462
|
+
peer,
|
|
3301
3463
|
)
|
|
3302
3464
|
script = (
|
|
3303
3465
|
"set -e; "
|
|
@@ -3432,6 +3594,13 @@ def _list_ota_smoke(args: argparse.Namespace) -> int:
|
|
|
3432
3594
|
|
|
3433
3595
|
|
|
3434
3596
|
def _ota_cleanup_hosts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
|
|
3597
|
+
if plan.install_mode == "checkout":
|
|
3598
|
+
# The workdir is the user's repository here. `rm -rf` on it would delete
|
|
3599
|
+
# a checkout with its untracked work — bags, instance artefacts, local
|
|
3600
|
+
# edits — to clean up files this mode never created. There is nothing to
|
|
3601
|
+
# remove: staging is what cleanup undoes, and staging did not happen.
|
|
3602
|
+
print("OTA smoke: nothing to clean up — checkout mode staged nothing.")
|
|
3603
|
+
return
|
|
3435
3604
|
_ota_validate_prepare_workdir(plan.workdir)
|
|
3436
3605
|
for peer in plan.peers.values():
|
|
3437
3606
|
_ota_run(
|
|
@@ -3497,7 +3666,7 @@ def _start_interactive_ota_smoke(args: argparse.Namespace) -> int:
|
|
|
3497
3666
|
print("Local control tmux prefix: Ctrl-b. Send the peer tmux/catmux prefix with Ctrl-b Ctrl-b.")
|
|
3498
3667
|
if target.target_type == "scenario":
|
|
3499
3668
|
for peer_name, peer in plan.peers.items():
|
|
3500
|
-
attach = _ota_rosotacom_command(plan, ["scenario", "attach", target.name, "--identity", peer_name])
|
|
3669
|
+
attach = _ota_rosotacom_command(plan, ["scenario", "attach", target.name, "--identity", peer_name], peer)
|
|
3501
3670
|
attach_cmd = _ota_quote_cmd(_ota_remote_argv(peer, attach, tty=bool(peer.ssh)))
|
|
3502
3671
|
print(f"Manual remote scenario reattach for {peer_name}: {attach_cmd}")
|
|
3503
3672
|
if mode == "attach":
|
|
@@ -6540,6 +6709,26 @@ def test_command(args: argparse.Namespace) -> int:
|
|
|
6540
6709
|
from . import bag_ground_truth
|
|
6541
6710
|
|
|
6542
6711
|
ground_truth = bag_ground_truth.bag_ground_truth(bag)
|
|
6712
|
+
elif not getattr(args, "suggest", False):
|
|
6713
|
+
# A `vs_bag_ratio` needs the bag's native rate, and without one it is
|
|
6714
|
+
# skipped rather than failed -- so the run would print TEST OK having
|
|
6715
|
+
# checked nothing about completeness. Refuse instead: the declaration
|
|
6716
|
+
# is the statement of intent, and honouring it or failing loudly is
|
|
6717
|
+
# this command's job.
|
|
6718
|
+
needs_bag = status_eval.topics_requiring_bag(expect_by_topic, profile)
|
|
6719
|
+
if needs_bag:
|
|
6720
|
+
listed = "\n".join(f" {base}" for base in needs_bag)
|
|
6721
|
+
print(
|
|
6722
|
+
f"rosotacom test: {len(needs_bag)} topic(s) declare "
|
|
6723
|
+
f"`completeness.vs_bag_ratio`, which compares the delivered rate "
|
|
6724
|
+
f"to the source's native rate and can only be evaluated against "
|
|
6725
|
+
f"the replay bag:\n{listed}\n"
|
|
6726
|
+
f"Pass `--bag <dir>`, or drop the assertion from a session that "
|
|
6727
|
+
f"is not replay-driven. Without a bag it would be skipped in "
|
|
6728
|
+
f"silence and this run would report success.",
|
|
6729
|
+
file=sys.stderr,
|
|
6730
|
+
)
|
|
6731
|
+
return 1
|
|
6543
6732
|
reports: dict[str, Any] = {}
|
|
6544
6733
|
failures: list[str] = []
|
|
6545
6734
|
|
|
@@ -8246,6 +8435,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
8246
8435
|
_add_peer_arg(ota_smoke_parser)
|
|
8247
8436
|
_add_peer_address_arg(ota_smoke_parser)
|
|
8248
8437
|
_add_peer_ssh_arg(ota_smoke_parser)
|
|
8438
|
+
ota_smoke_parser.add_argument(
|
|
8439
|
+
"--peer-checkout",
|
|
8440
|
+
action="append",
|
|
8441
|
+
default=[],
|
|
8442
|
+
metavar="PEER=PATH",
|
|
8443
|
+
help=(
|
|
8444
|
+
"Absolute path of a peer's project checkout, for --install-mode checkout. "
|
|
8445
|
+
"Required for every peer in that mode; the same repository is at a different path on each machine."
|
|
8446
|
+
),
|
|
8447
|
+
)
|
|
8249
8448
|
ota_smoke_parser.add_argument("--target-type", choices=["auto", "session", "scenario"], default="auto")
|
|
8250
8449
|
ota_smoke_parser.add_argument("--interactive", action="store_true", help="Open a local control tmux UI.")
|
|
8251
8450
|
ota_smoke_parser.add_argument("--stop", action="store_true", help="Stop an OTA smoke run.")
|
|
@@ -8269,7 +8468,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
8269
8468
|
help=(
|
|
8270
8469
|
"How the peers get rosotacom. 'source' (default) stages and installs what you are running — "
|
|
8271
8470
|
"right while iterating on rosotacom. 'pin' installs a published release from the index, so the "
|
|
8272
|
-
"peers run the artefact that ships — right when rehearsing a deployment."
|
|
8471
|
+
"peers run the artefact that ships — right when rehearsing a deployment. 'checkout' stages and "
|
|
8472
|
+
"installs nothing: each peer uses its own installed rosotacom and its own project checkout "
|
|
8473
|
+
"(see --peer-checkout), so the run tests the machines as git left them."
|
|
8273
8474
|
),
|
|
8274
8475
|
)
|
|
8275
8476
|
ota_smoke_parser.add_argument(
|
|
@@ -105,6 +105,27 @@ def resolve_expect_for_profile(expect: dict[str, Any], profile: str | None) -> d
|
|
|
105
105
|
return resolved
|
|
106
106
|
|
|
107
107
|
|
|
108
|
+
def topics_requiring_bag(expect_by_topic: dict[str, dict[str, Any]], profile: str | None = None) -> list[str]:
|
|
109
|
+
"""Topics whose expectations can only be evaluated against a replay bag.
|
|
110
|
+
|
|
111
|
+
`completeness.vs_bag_ratio` compares the delivered rate to the *source's*
|
|
112
|
+
native rate, which only a bag knows. `_check_bag_completeness` returns
|
|
113
|
+
early when no ground truth was supplied, so without `--bag` such an
|
|
114
|
+
expectation is skipped in silence and the run still prints `TEST OK`.
|
|
115
|
+
|
|
116
|
+
A skipped assertion reads as coverage, which is worse than no assertion at
|
|
117
|
+
all: it is the exact shape of the defect these contracts exist to catch.
|
|
118
|
+
The caller uses this to refuse the run instead.
|
|
119
|
+
"""
|
|
120
|
+
required = []
|
|
121
|
+
for base, raw in sorted((expect_by_topic or {}).items()):
|
|
122
|
+
expect = resolve_expect_for_profile(raw or {}, profile)
|
|
123
|
+
completeness = expect.get("completeness") or {}
|
|
124
|
+
if isinstance(completeness, dict) and completeness.get("vs_bag_ratio") is not None:
|
|
125
|
+
required.append(base)
|
|
126
|
+
return required
|
|
127
|
+
|
|
128
|
+
|
|
108
129
|
def expectations_from_cfg(cfg: dict[str, Any]) -> dict[str, dict[str, Any]]:
|
|
109
130
|
"""Map a topic's base name -> its `expect` block, from a session config."""
|
|
110
131
|
out: dict[str, dict[str, Any]] = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev7
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -460,6 +460,11 @@ rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
|
460
460
|
--install-mode pin # defaults to your own version
|
|
461
461
|
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
462
462
|
--install-mode pin --install-pin 2.4
|
|
463
|
+
|
|
464
|
+
# test the machines as they are: no staging, no install, their own checkouts
|
|
465
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
466
|
+
--peer-ssh b=robot-b --install-mode checkout \
|
|
467
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt
|
|
463
468
|
```
|
|
464
469
|
|
|
465
470
|
`source` is right while iterating on rosotacom itself — the peers run the code
|
|
@@ -469,6 +474,23 @@ missing from the wheel, an undeclared dependency) fails in the rehearsal instead
|
|
|
469
474
|
of on the target machine. `source` cannot catch that class of defect by
|
|
470
475
|
construction, because it never builds the artefact that ships.
|
|
471
476
|
|
|
477
|
+
`checkout` answers a different question again: not "does this artefact work" but
|
|
478
|
+
"is *this machine* ready". Nothing is staged and nothing is installed — each
|
|
479
|
+
peer runs the rosotacom it already has, from the project checkout it already
|
|
480
|
+
has, so what is under test is the state git and the machine's own install left
|
|
481
|
+
behind, dependency pins included. Ground truth moves into the repository: push,
|
|
482
|
+
pull, run. It is also the only mode in which a project may reference anything
|
|
483
|
+
outside its own directory — staging copies the project directory, so a mount or
|
|
484
|
+
config path leading above it cannot survive the copy and fails on the peer as a
|
|
485
|
+
missing path.
|
|
486
|
+
|
|
487
|
+
Because the same repository sits at a different absolute path on every machine,
|
|
488
|
+
`--peer-checkout` is required for every peer; the path *inside* the repository
|
|
489
|
+
is taken from your own checkout, so the project has to live in one. Preparation
|
|
490
|
+
becomes verification: each peer is asked whether the checkout, the project file
|
|
491
|
+
and `rosotacom` are there, and each version is printed. `--cleanup` does nothing
|
|
492
|
+
in this mode — there is no staging to undo, and the workdir is your repository.
|
|
493
|
+
|
|
472
494
|
The run manifest records which mode and which version the peers ran, so a result
|
|
473
495
|
can be attributed to an artefact rather than to a working copy.
|
|
474
496
|
|