Skip to content

Test what cont-init turns options.json into - #583

Open
MaxWinterstein wants to merge 2 commits into
mainfrom
test/tgtg-cont-init
Open

Test what cont-init turns options.json into#583
MaxWinterstein wants to merge 2 commits into
mainfrom
test/tgtg-cont-init

Conversation

@MaxWinterstein

Copy link
Copy Markdown
Owner

The first test in this repo that actually runs an add-on. Everything until now built images and never started one.

What it covers

Home Assistant only allows two levels of nesting in add-on options, so config.yaml flattens intense_fetch into two sibling keys and cont-init uses jq to fold them back into the nested shape the bridge reads:

jq ".tgtg += { intense_fetch: { interval: .tgtg.intense_fetch_interval, period_of_time: .tgtg.intense_fetch_period_of_time}}"

Nothing checked that, and it is exactly the kind of transform that breaks quietly. jq's += writes null for a key that isn't there rather than failing, so the bridge starts with a broken intense_fetch and you find out from an issue report.

The test runs the real cont-init inside the freshly built image against a synthetic /data/options.json and asserts the output — including the negative case, that a config missing those keys yields nulls. That second assertion is the machine-readable reason DOCS.md has to keep listing them (which is what #576 fixed).

Two implementation notes worth reviewing

No mock Supervisor is needed here, and I checked rather than assumed. bashio::config reads options from the Supervisor REST API, not from /data/options.json, so a naive docker run -v options.json:/data/options.json proves nothing for most add-ons. This one is the exception: its cont-init only calls bashio::log.* and bashio::fs.file_exists, neither of which touches the API. Add-ons that do call bashio::config will need a small mock sidecar.

bashio is invoked as the interpreter rather than running the script directly:

docker run --entrypoint /bin/bash "$IMAGE" -c "/usr/bin/bashio $SCRIPT && cat $SETTINGS"

The script's shebang is #!/usr/bin/with-contenv bashio, and with-contenv needs s6's /run/s6/container_environment, which doesn't exist outside a real Supervisor. Going through bashio directly works because its runner is BASH_ARGV0=${1:?}; shift; source "$0" "$@".

Wiring

addon-tests discovers participants by globbing */test/*.test.sh, so adding a test to another add-on needs no workflow edit. planefence already has a test/options.json and is correctly not picked up.

It is a separate job, not a step inside check-build, because check-build only runs for add-ons whose config.* changed — so a test-only or rootfs/-only change would never run its own test. That is the same class of bug as #579.

Honest caveat

I can't run Docker in my environment, so this PR's CI run is the first real execution of this test. If it's red, that's me iterating, not the add-on being broken — I'll fix it from the logs. The shell itself is shellcheck-clean and the discovery logic I did verify locally.

🤖 Generated with Claude Code

Home Assistant only allows two levels of nesting in add-on options, so
config.yaml flattens intense_fetch into two sibling keys and cont-init
uses jq to fold them back into the nested shape the bridge reads.
Nothing checked that, and it is the kind of transform that breaks
quietly: jq's += writes null for a key that is not there rather than
failing, so the bridge starts with a broken intense_fetch.

The test runs the real cont-init inside the built image against a
synthetic /data/options.json and asserts the result, including that a
config missing those keys yields nulls. That second case is why DOCS.md
has to keep listing them.

Invoking bashio as the interpreter rather than running the script
directly skips the with-contenv dependency on s6's container_environment,
which does not exist outside a real Supervisor. Nothing here needs the
Supervisor API: this add-on's cont-init only uses bashio::log.* and
bashio::fs.file_exists.

The job discovers add-ons by looking for test/*.test.sh, so adding a
test elsewhere needs no workflow change. It is a separate job rather
than a step in check-build because that job only runs for add-ons whose
config.* changed, so a test-only or rootfs-only change would never run
its own test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 21 minutes.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 65217e73-3e46-4559-8f01-bd95ca4ffb04

📥 Commits

Reviewing files that changed from the base of the PR and between ab9b2e2 and 326d308.

📒 Files selected for processing (3)
  • .github/workflows/onpr_check-pr.yaml
  • toogoodtogo-ha-mqtt-bridge/test/cont-init.test.sh
  • toogoodtogo-ha-mqtt-bridge/test/options.json

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.

The typos hook rewrote all 13 to io.hash while this branch was being
prepared. Those are the labels Supervisor reads. #585 pins the word so
it cannot happen again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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