Skip to content

feat: TestingBase pilot — submodule + XML validation + plugin smoke (2026.5.4)#58

Open
simons-plugins wants to merge 14 commits into
mainfrom
feat/testingbase-pilot
Open

feat: TestingBase pilot — submodule + XML validation + plugin smoke (2026.5.4)#58
simons-plugins wants to merge 14 commits into
mainfrom
feat/testingbase-pilot

Conversation

@simons-plugins
Copy link
Copy Markdown
Owner

@simons-plugins simons-plugins commented May 4, 2026

Summary

First adoption of TestingBase in this workspace. Establishes the upstream-strict two-venv layout as the workspace standard for live integration tests, validated end-to-end on local Indigo 2025.2.

Design and rationale: docs/plans/2026-05-04-netro-testingbase-pilot-design.md (committed in this branch).

What's added

TestingBase scaffolding:

  • tests/shared/ — TestingBase submodule pinned to upstream main (3fe47ef)
  • tests/testing-requirements.txt — chains to shared/module-requirements.txt plus adds pytest (upstream's chain doesn't include it)
  • tests/.env.example — committed template; real .env is gitignored
  • tests/integration/__init__.py — package marker with run instructions

Live tests (run via dedicated venv):

  • tests/integration/test_xml_validation.py — 5 ValidateXmlFile classes covering Actions/Devices/Events/MenuItems/PluginConfig.xml. Schema validation, no Indigo runtime needed for the validation itself.
  • tests/integration/test_indigo_smoke.py — single APIBase test asserting com.simons-plugins.netro is loaded and enabled in the running Indigo server.
  • tests/integration/pytest.ini — empty addopts so the integration suite isolates from the main env's coverage flags (which require pytest-cov, deliberately not in the integration venv).

Wiring:

  • pytest.ini and pyproject.toml: norecursedirs = tests/integration tests/shared tests/venv. Verified — pytest --collect-only from main env collects all 508 Pattern A tests across 13 files and 0 TestingBase tests.
  • .gitignore: adds tests/.env and tests/venv/.
  • tests/README.md: documents Pattern A + Pattern B for new contributors.

Delivery:

  • PluginVersion 2026.5.3 → 2026.5.4 (patch — test infra change, no user-facing behaviour).

Test plan

  • pytest from main env (Pattern A): all 508 existing tests still discovered and pass; 0 TestingBase tests collected
  • source tests/venv/bin/activate && pytest tests/integration/: 6 tests pass (5 XML + 1 smoke). Author runs locally — sandbox can't reach /usr/local/indigo/indigo-host
  • On first green smoke run: disable netro in Indigo and re-run — if test stays green, the enabled field doesn't discriminate and we need a different key (per code review feedback)
  • git submodule status shows tests/shared initialised at 3fe47ef
  • tests/.env is gitignored, tests/.env.example is committed

Out of scope (deferred)

  • CI integration for Pattern B — TestingBase requires a locally-installed Indigo (/usr/local/indigo/indigo-host) which CI runners don't have. CI continues to run only Pattern A.
  • Workspace CLAUDE.md standard update — separate PR after this lands.
  • Rolling out to other plugins (heatmiser, home-intelligence, UK-Trains) — separate PRs after this proves out.

Follow-up notes (out of scope here)

  • The repo has duplicate pytest config in pytest.ini and pyproject.toml [tool.pytest.ini_options]. Pre-existing tech debt; consolidating is its own cleanup task. We added norecursedirs to both to keep them in sync.
  • tests/README.md hardcodes the python.org Python 3.13 framework path. Developers using Homebrew Python 3.13 will need to substitute. Could be polished to a less prescriptive instruction in a follow-up.
  • The smoke test guesses enabled as the discriminating field on Indigo's plugin object. Need to verify on first green run that disabling the plugin actually flips this — if not, switch to whichever field is right.

Branch structure

12 commits on top of main, in logical order: design → plan → infra setup → tests → wiring → docs → version bump. Each commit is small and reviewable on its own.

Summary by CodeRabbit

Release Notes

  • Chores
    • Bumped plugin version to 2026.5.4 with enhanced integration testing framework for improved plugin stability and validation.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Warning

Rate limit exceeded

@simons-plugins has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 26 minutes and 45 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e5a58e64-ca45-4890-8eee-8d1260329230

📥 Commits

Reviewing files that changed from the base of the PR and between 58f0335 and 3ae3b97.

📒 Files selected for processing (15)
  • .gitignore
  • .gitmodules
  • Netro Sprinklers.indigoPlugin/Contents/Info.plist
  • docs/plans/2026-05-04-netro-testingbase-pilot-design.md
  • docs/plans/2026-05-04-netro-testingbase-pilot-plan.md
  • pyproject.toml
  • pytest.ini
  • tests/.env.example
  • tests/README.md
  • tests/integration/__init__.py
  • tests/integration/pytest.ini
  • tests/integration/test_indigo_smoke.py
  • tests/integration/test_xml_validation.py
  • tests/shared
  • tests/testing-requirements.txt
📝 Walkthrough

Walkthrough

This PR establishes a two-environment integration testing framework by adding a TestingBase submodule for live HTTP tests against an Indigo server, with XML validation and plugin-load verification, separate pytest configuration to isolate integration tests from main unit tests, and documentation of the new testing pattern.

Changes

Integration Testing Infrastructure

Layer / File(s) Summary
Dependency & Gitignore
.gitignore, .gitmodules, tests/shared
Git configuration now ignores test artifacts (tests/.env, tests/venv/) under a TestingBase section and registers tests/shared as a submodule pointing to IndigoDomotics/TestingBase.
Test Environment Configuration
tests/.env.example, tests/testing-requirements.txt
Environment variables template documents API keys, URL prefixes, plugin ID, logging, and timing controls. Requirements file chains to the submodule's module-requirements.txt and adds pytest.
Test Discovery & Isolation
pyproject.toml, pytest.ini, tests/integration/pytest.ini
Pytest configuration prevents the main environment from recursing into tests/integration/, tests/shared/, and tests/venv/. Integration suite uses its own isolated pytest.ini to avoid inheriting coverage settings.
Integration Test Suite
tests/integration/__init__.py, tests/integration/test_xml_validation.py, tests/integration/test_indigo_smoke.py
Module docstring provides setup instructions; five test classes validate XML files (Actions.xml, Devices.xml, Events.xml, MenuItems.xml, PluginConfig.xml) against schema via ValidateXmlFile; one smoke test queries Indigo plugins endpoint to verify the plugin is loaded and enabled.
Documentation & Version Bump
tests/README.md, docs/plans/*, Netro Sprinklers.indigoPlugin/Contents/Info.plist
Tests README documents Pattern A (mocked unit tests) vs Pattern B (live integration). Design and plan documents detail architecture, test coverage, and verification steps. Plugin version bumped from 2026.5.3 to 2026.5.4.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit's ode to testing glory:
Tests now run in two-venv story,
XML checked, plugin smoke-tested bright,
TestingBase submodule locked just right.
From integration flows to docs so clear—
Live Indigo testing is finally here! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main changes: introducing TestingBase pilot with submodule integration, XML validation tests, plugin smoke test, and a version bump to 2026.5.4.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/testingbase-pilot

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
tests/shared (1)

1-1: 💤 Low value

Submodule pinned to a specific commit — LGTM.

Pinning tests/shared to an explicit commit SHA (3fe47ef) rather than a moving ref is the right call for reproducible integration runs. As an optional follow-up, if the upstream TestingBase repo publishes tagged releases, consider tracking a tag instead of a commit on main so submodule bumps map to versioned upstream changes; otherwise this is fine as-is.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/shared` at line 1, No code change required—the submodule "tests/shared"
is correctly pinned to commit 3fe47ef for reproducible runs; if you want an
optional follow-up, switch the submodule ref from the commit SHA to an upstream
release tag (if TestingBase publishes tags) by updating the gitlink to that tag
and committing the submodule change so future bumps map to versioned releases
instead of a raw commit.
.gitignore (1)

53-55: 💤 Low value

Redundant entries — already covered by the top-level patterns.

tests/.env is already ignored by .env (Line 42), and tests/venv/ is already ignored by venv/ (Line 8) — git applies both patterns recursively to all subdirectories. The new entries are harmless but add noise.

♻️ Simplification (keeping the intent clear via comment alone)
-# TestingBase — gitignored test creds and dedicated venv
-tests/.env
-tests/venv/
+# TestingBase — tests/.env and tests/venv/ are already excluded by .env and venv/ above
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.gitignore around lines 53 - 55, Remove the redundant specific ignore lines
for tests/.env and tests/venv/ from .gitignore because they are already covered
by the global patterns .env and venv/ (which apply recursively); update the file
by deleting the two lines "tests/.env" and "tests/venv/" and, if needed, keep or
add a brief comment indicating that .env and venv/ cover test subdirectories to
preserve intent.
tests/integration/test_indigo_smoke.py (1)

26-36: 💤 Low value

f'state=found' has an f-prefix with no interpolation — minor anti-pattern.

The generated line f'state=found' (line 31 of the script source) is a redundant f-string. It's harmless and functionally correct since it's concatenated with the adjacent f-strings that do have interpolations, but a plain 'state=found' is cleaner.

♻️ Remove spurious f-prefix
-            f"    f'state=found'\n"
+            f"    'state=found'\n"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/test_indigo_smoke.py` around lines 26 - 36, The script
string uses a redundant f-string for the literal "state=found"; in the
multi-line construction assigned to variable script (where plugin is fetched via
indigo.server.getPlugin(self.plugin_id) and
plugin.isInstalled()/isEnabled()/isRunning() are interpolated), change
f'state=found' to a plain 'state=found' to remove the spurious f-prefix while
leaving the other f-strings intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/integration/test_xml_validation.py`:
- Around line 1-6: Update the module docstring in
tests/integration/test_xml_validation.py to clarify that although the Indigo
server process need not be manually started, APIBase.setUpClass runs in the test
MRO and spawns the indigo-host process, so Indigo must be installed locally for
the tests to run; reference APIBase.setUpClass and indigo-host in the text so
contributors understand the actual installation requirement.

---

Nitpick comments:
In @.gitignore:
- Around line 53-55: Remove the redundant specific ignore lines for tests/.env
and tests/venv/ from .gitignore because they are already covered by the global
patterns .env and venv/ (which apply recursively); update the file by deleting
the two lines "tests/.env" and "tests/venv/" and, if needed, keep or add a brief
comment indicating that .env and venv/ cover test subdirectories to preserve
intent.

In `@tests/integration/test_indigo_smoke.py`:
- Around line 26-36: The script string uses a redundant f-string for the literal
"state=found"; in the multi-line construction assigned to variable script (where
plugin is fetched via indigo.server.getPlugin(self.plugin_id) and
plugin.isInstalled()/isEnabled()/isRunning() are interpolated), change
f'state=found' to a plain 'state=found' to remove the spurious f-prefix while
leaving the other f-strings intact.

In `@tests/shared`:
- Line 1: No code change required—the submodule "tests/shared" is correctly
pinned to commit 3fe47ef for reproducible runs; if you want an optional
follow-up, switch the submodule ref from the commit SHA to an upstream release
tag (if TestingBase publishes tags) by updating the gitlink to that tag and
committing the submodule change so future bumps map to versioned releases
instead of a raw commit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 19a14d3e-17b9-4575-a61f-07ea67b3e2b6

📥 Commits

Reviewing files that changed from the base of the PR and between c7048fd and 58f0335.

📒 Files selected for processing (15)
  • .gitignore
  • .gitmodules
  • Netro Sprinklers.indigoPlugin/Contents/Info.plist
  • docs/plans/2026-05-04-netro-testingbase-pilot-design.md
  • docs/plans/2026-05-04-netro-testingbase-pilot-plan.md
  • pyproject.toml
  • pytest.ini
  • tests/.env.example
  • tests/README.md
  • tests/integration/__init__.py
  • tests/integration/pytest.ini
  • tests/integration/test_indigo_smoke.py
  • tests/integration/test_xml_validation.py
  • tests/shared
  • tests/testing-requirements.txt

Comment on lines +1 to +6
"""ValidateXmlFile coverage for all 5 netro plugin XML files.

These tests don't need Indigo running — they validate the XML
files on disk against TestingBase's bundled schema. Catch broken
XML before it reaches end users.
"""
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Docstring understates the Indigo installation requirement

"These tests don't need Indigo running" is technically true (the Indigo server needn't be up), but because APIBase is in the MRO, APIBase.setUpClass still executes and spawns indigo-host, which requires Indigo to be installed locally. The README already captures this accurately; the module docstring should match to avoid misleading a contributor who might attempt to run these tests in an environment without Indigo installed (e.g., CI).

📝 Proposed docstring clarification
-These tests don't need Indigo running — they validate the XML
-files on disk against TestingBase's bundled schema. Catch broken
-XML before it reaches end users.
+These tests validate XML files on disk against TestingBase's bundled
+schema; the Indigo *server* does not need to be running. However,
+``APIBase`` is in the MRO so ``APIBase.setUpClass`` still executes
+and requires Indigo to be installed locally (it spawns ``indigo-host``
+to resolve the install path). Run from the dedicated integration venv.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"""ValidateXmlFile coverage for all 5 netro plugin XML files.
These tests don't need Indigo runningthey validate the XML
files on disk against TestingBase's bundled schema. Catch broken
XML before it reaches end users.
"""
"""ValidateXmlFile coverage for all 5 netro plugin XML files.
These tests validate XML files on disk against TestingBase's bundled
schema; the Indigo *server* does not need to be running. However,
``APIBase`` is in the MRO so ``APIBase.setUpClass`` still executes
and requires Indigo to be installed locally (it spawns ``indigo-host``
to resolve the install path). Run from the dedicated integration venv.
"""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/test_xml_validation.py` around lines 1 - 6, Update the
module docstring in tests/integration/test_xml_validation.py to clarify that
although the Indigo server process need not be manually started,
APIBase.setUpClass runs in the test MRO and spawns the indigo-host process, so
Indigo must be installed locally for the tests to run; reference
APIBase.setUpClass and indigo-host in the text so contributors understand the
actual installation requirement.

simons-plugins and others added 14 commits May 9, 2026 21:02
Captures the approved design before implementation:

- Approach: upstream-strict two-venv layout (tests/shared submodule
  + tests/venv + tests/testing-requirements.txt). Picked over a pytest-
  unified single-venv approach because it works uniformly across all
  workspace plugins (most don't have pyproject.toml) and matches what
  other Indigo plugin developers use.
- Pilot scope: ValidateXmlFile across all 5 netro XML files
  (Actions/Devices/Events/MenuItems/PluginConfig) plus one APIBase
  smoke test that fetches Indigo's plugin list and asserts netro is
  loaded. No netro hardware required.
- Environment: local Indigo 2025.2 sandbox via dev license. jarvis
  stays on 2025.1 for now.
- Intent: full workspace adoption. Pilot exists to learn the
  mechanics; rollout to heatmiser/home-intelligence/UK-Trains plus
  workspace CLAUDE.md update is follow-on work.

Implementation plan to follow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 bite-sized tasks covering submodule setup, venv creation, env
template, ValidateXmlFile coverage of all 5 netro XML files, the
APIBase plugin-loaded smoke test, pytest config to keep main env
clean, tests/README.md, and version bump + PR.

Companion to the design doc in the same folder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…test discovery

The TestingBase pilot adds three subtrees under tests/ that the main
pytest env can't import:

- tests/integration/ — APIBase / ValidateXmlFile tests; require
  the dedicated venv
- tests/shared/ — TestingBase submodule, ships its own example tests
  (example_test_xml_files.py) that fail without the dedicated venv
- tests/venv/ — pytest-internal test files inside the venv itself

Adding norecursedirs to both pytest.ini (active config) and
pyproject.toml's [tool.pytest.ini_options] block (kept in sync for
tooling that reads pyproject) so a casual `pytest` from netro's main
env still passes cleanly.

Verified: `pytest --collect-only` collects all 508 existing Pattern A
tests across 13 files and 0 TestingBase tests.

Note for follow-up: the duplication of pytest config across pytest.ini
and pyproject.toml is pre-existing technical debt; consolidating to
one file is a separate cleanup task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related fixes the plan didn't anticipate:

- tests/testing-requirements.txt: add `pytest`. Upstream's
  module-requirements.txt installs python-dotenv and httpx but
  not pytest, so the integration venv couldn't run the tests
  without a separate manual pip install.
- tests/integration/pytest.ini: empty `addopts` so the integration
  suite ignores the main netro pytest.ini's coverage flags. Those
  flags require pytest-cov (which isn't in this venv) and produce
  meaningless output for integration tests anyway since they don't
  import netro source. Pytest's rootdir search picks up this
  inner config first when running tests under tests/integration/.

Verified: from tests/, `venv/bin/pytest integration/ --collect-only`
collects exactly the 6 expected tests (5 ValidateXmlFile + 1
APIBase smoke) with no command-line overrides needed.

Note: this adds a third pytest config file in the repo. Unlike the
pytest.ini/pyproject.toml duplication (pre-existing tech debt, same
scope), this one is integration-scoped — different responsibility,
not duplicate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…TP endpoint

The original smoke test guessed at an `indigo.plugins` HTTP endpoint that
doesn't exist. Indigo's HTTP API only exposes devices, variables,
actionGroups, controlPages, logs, triggers, and schedules. Plugin state
isn't queryable via HTTP at all.

Switch to the IOM via `run_host_script` (TestingBase's wrapper around
`indigo-host -e <script>`). Two corrections vs. the prior attempt:

1. Use `indigo.server.getPlugin(pluginId)` — documented in
   docs/plugin-dev/api/iom/command-namespaces.md (loaded via /indigo:dev).
   The returned object exposes isInstalled(), isEnabled(), isRunning().
2. Use `return`, not `print`. `indigo-host -e` wraps the script as a
   function body and `print()` goes to Indigo's event log, not the
   subprocess stdout. Upstream's own tests/shared/utils.py:get_install_folder
   uses the same `return` convention.

Result: 6/6 integration tests green against local Indigo 2025.2 via the
clarkcastle-dev reflector (5 ValidateXmlFile + this smoke test), in
about 15s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@simons-plugins simons-plugins force-pushed the feat/testingbase-pilot branch from 58f0335 to 3ae3b97 Compare May 9, 2026 20:02
@simons-plugins
Copy link
Copy Markdown
Owner Author

Rebased onto main (workflow PR #59 merged). Bumped PluginVersion 2026.5.4 → 2026.5.6 because v2026.5.5 was just tagged by the workflow PR's release. Note: the existing 'chore: bump PluginVersion to 2026.5.4' commit message is now stale — actual bump is to 2026.5.6. PR title/description still reference 2026.5.4 but can be updated when convenient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant