SWS-12500-custom-component/tests
SchiZzA 0400a9cdee feat(migration): adopt predecessor integration entities, keeping history
The integration is moving to a new repository under a new domain. Home Assistant
keys recorder history and long-term statistics on entity_id, not on the domain,
so the move is free provided the registry entries are carried over instead of
recreated. A recreated entity gets a fresh entity_id and its history is orphaned.

predecessor.py does the carry-over with async_update_entity_platform, which
rewrites platform and config_entry_id and leaves entity_id alone. Everything the
user set by hand rides along, because the registry row itself survives: renames,
icons, areas, labels, categories, hidden and disabled state.

Guards, each one covered by a test that fails when it is removed:

- The startup placeholder state (unavailable + ATTR_RESTORED) is cleared first,
  because async_update_entity_platform accepts only a missing or unknown state.
- A state that is not a placeholder means an integration is still driving the
  entity, so it is refused rather than moved out from under a live platform.
- A unique_id already taken under our own domain is refused. Home Assistant does
  not check this itself: the duplicate guard in _async_update_entity only runs
  when new_unique_id is passed.
- Devices are repointed before the old entry is removed. A device that loses its
  last config entry is deleted, and that takes its entities with it.
- The old config entry is removed only when every entity made it across.
  Otherwise it stays, a retry stays possible, and nothing is lost.

Options are inherited in a separate, earlier pass. Adopting the registry alone
is not enough: SENSORS_TO_LOAD decides which entities the platform creates, so
an empty one leaves every adopted entry showing "no longer provided" until a
payload arrives, and derived sensors are never in a payload at all. The merge is
predecessor-fills-gaps, so anything just entered in the config flow wins. The
version 1 spelling of the Pocasi Meteo flag is translated on the way in, since
async_migrate_entry runs against this entry's own version and would never look
at a key copied in afterwards.

The two passes run at different points in async_setup_entry. Options first,
before the coordinator and routes read them, or an inherited WSLINK flag would
leave the entry listening on the wrong endpoint until a reload. Adoption after
the routes are proven but before async_forward_entry_setups, so the one
destructive step cannot run in a setup that then fails, and so our platforms
bind to the adopted registry entries rather than to freshly created ones.

Two problems the migration surfaced, fixed here as well:

- register_path now catches ValueError alongside RuntimeError and raises
  ConfigEntryNotReady with a message naming HACS. aiohttp rejects a duplicate
  route name with ValueError, and the route names are fixed rather than
  domain-scoped, so a user who has not yet removed the old version hit an
  unhandled traceback.
- add_new_sensors applies the derived-sensor expansion that async_setup_entry
  already applied. Derived sensors are computed, never sent, so discovery can
  only offer their inputs; the azimut unlocked by a newly discovered wind
  direction went missing until the next restart. Only the sensors this batch
  unlocks are added, so nothing is created twice.

PREDECESSOR_DOMAIN equals DOMAIN for now, which short-circuits the whole pass.
It stays correct until the day the domain changes.
2026-07-26 22:08:01 +02:00
..
conftest.py Add HCHO / VOC air-quality sensors (T9 module) 2026-05-11 23:55:36 +02:00
test_battery_classification.py feat(wslink): implement every sensor the WSLink API v0.6 defines 2026-07-26 15:20:07 +02:00
test_binary_battery.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
test_config_flow.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
test_conflicts.py Add tests for legacy/Ecowitt protocol conflict 2026-07-25 21:47:54 +02:00
test_const.py no-mistakes(review): Migrate Pocasi option key, fix typos and Windy status 2026-07-25 22:12:55 +02:00
test_data.py fix: block enabling legacy and Ecowitt protocols together 2026-07-25 21:47:53 +02:00
test_diagnostics.py test: reach 100% coverage of custom_components/sws12500 2026-07-25 21:47:51 +02:00
test_ecowitt_bridge.py Add tests for legacy/Ecowitt protocol conflict 2026-07-25 21:47:54 +02:00
test_health.py fix: Prevent addon probe from failing config entry 2026-07-25 21:47:53 +02:00
test_init.py fix(document): Refresh runtime route docs 2026-07-26 12:03:37 +02:00
test_integration_lifecycle.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
test_pocasi_ecowitt.py fix(review): stop counting timeouts, notify on disable, drop WSLink indoor 2026-07-26 13:25:39 +02:00
test_pocasi_push.py fix(review): parse battery flags via to_int, release routes on removal 2026-07-26 15:53:03 +02:00
test_predecessor_adoption.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
test_received_data.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
test_received_ecowitt.py feat(sws12500): forward Ecowitt payloads to Windy and Pocasi Meteo 2026-07-26 11:50:11 +02:00
test_routes.py Make routes method-aware and update related tests 2026-07-25 21:47:47 +02:00
test_routes_more.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
test_sensor_platform.py feat(migration): adopt predecessor integration entities, keeping history 2026-07-26 22:08:01 +02:00
test_sensors_common.py Add health diagnostic sensor and extensive tests for sws12500 2026-07-25 21:45:08 +02:00
test_sensors_weather.py Add health diagnostic sensor and extensive tests for sws12500 2026-07-25 21:45:08 +02:00
test_sensors_wslink.py fix(correctness): reload-window guards, rate-limit races, ecowitt flush, dt_util 2026-07-25 21:47:52 +02:00
test_staleness_legacy.py test: reach 100% coverage of custom_components/sws12500 2026-07-25 21:47:51 +02:00
test_strings.py no-mistakes(document): Update README for Ecowitt, Windy and diagnostics changes 2026-07-25 22:37:28 +02:00
test_t9_air_quality.py feat(wslink): implement every sensor the WSLink API v0.6 defines 2026-07-26 15:20:07 +02:00
test_translations_cs.py Add health diagnostic sensor and extensive tests for sws12500 2026-07-25 21:45:08 +02:00
test_translations_en.py Add health diagnostic sensor and extensive tests for sws12500 2026-07-25 21:45:08 +02:00
test_utils.py Add health diagnostic sensor and extensive tests for sws12500 2026-07-25 21:45:08 +02:00
test_utils_conv.py fix(security)+i18n: stop health-attribute leak, mask secrets in logs, sync translations 2026-07-25 21:47:52 +02:00
test_utils_more.py fix(review): parse battery flags via to_int, release routes on removal 2026-07-26 15:53:03 +02:00
test_weather_sensor_entity.py feat(device): merge all entities into one shared device with station-type model 2026-07-25 21:47:53 +02:00
test_windy_func.py Add health diagnostic sensor and extensive tests for sws12500 2026-07-25 21:45:08 +02:00
test_windy_more.py fix(review): clamp heat index, unify Windy uv, bound forward timeouts 2026-07-26 13:13:05 +02:00
test_windy_push.py fix(review): stop counting timeouts, notify on disable, drop WSLink indoor 2026-07-26 13:25:39 +02:00
test_wslink_api_coverage.py fix(review): persist WSLink probe types and harden flag parsing 2026-07-26 15:41:30 +02:00
test_wslink_derived_indices.py fix(review): clamp heat index, unify Windy uv, bound forward timeouts 2026-07-26 13:13:05 +02:00
test_wslink_e2e_upload.py fix(document): Drop stale WSLink TODO preamble, refresh binary sensor docs 2026-07-26 16:28:05 +02:00