hass.tibber_prices/developer/critical-patterns.html
github-actions[bot] e9aea64a2e deploy: 6898c126e3
2025-12-06 01:42:39 +00:00

244 lines
No EOL
52 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-critical-patterns" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.9.2">
<title data-rh="true">Critical Behavior Patterns - Testing Guide | Tibber Prices - Developer Guide</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://jpawlowski.github.io/hass.tibber_prices/developer/img/social-card.png"><meta data-rh="true" name="twitter:image" content="https://jpawlowski.github.io/hass.tibber_prices/developer/img/social-card.png"><meta data-rh="true" property="og:url" content="https://jpawlowski.github.io/hass.tibber_prices/developer/critical-patterns"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Critical Behavior Patterns - Testing Guide | Tibber Prices - Developer Guide"><meta data-rh="true" name="description" content="Purpose: This documentation lists essential behavior patterns that must be tested to ensure production-quality code and prevent resource leaks."><meta data-rh="true" property="og:description" content="Purpose: This documentation lists essential behavior patterns that must be tested to ensure production-quality code and prevent resource leaks."><link data-rh="true" rel="icon" href="/hass.tibber_prices/developer/img/logo.svg"><link data-rh="true" rel="canonical" href="https://jpawlowski.github.io/hass.tibber_prices/developer/critical-patterns"><link data-rh="true" rel="alternate" href="https://jpawlowski.github.io/hass.tibber_prices/developer/critical-patterns" hreflang="en"><link data-rh="true" rel="alternate" href="https://jpawlowski.github.io/hass.tibber_prices/developer/critical-patterns" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Critical Behavior Patterns - Testing Guide","item":"https://jpawlowski.github.io/hass.tibber_prices/developer/critical-patterns"}]}</script><link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&amp;family=Space+Grotesk:wght@500;600;700&amp;display=swap"><link rel="stylesheet" href="/hass.tibber_prices/developer/assets/css/styles.be4f3d68.css">
<script src="/hass.tibber_prices/developer/assets/js/runtime~main.09b7b31a.js" defer="defer"></script>
<script src="/hass.tibber_prices/developer/assets/js/main.5eb4cf38.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<svg style="display: none;"><defs>
<symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol>
</defs></svg>
<script>!function(){var t=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();document.documentElement.setAttribute("data-theme",t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")),document.documentElement.setAttribute("data-theme-choice",t||"system")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><link rel="preload" as="image" href="/hass.tibber_prices/developer/img/logo.svg"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="theme-layout-navbar navbar navbar--fixed-top"><div class="navbar__inner"><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/hass.tibber_prices/developer/"><div class="navbar__logo"><img src="/hass.tibber_prices/developer/img/logo.svg" alt="Tibber Prices Integration Logo" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="/hass.tibber_prices/developer/img/logo.svg" alt="Tibber Prices Integration Logo" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><b class="navbar__title text--truncate">Tibber Prices HA</b></a><a class="navbar__item navbar__link" href="/hass.tibber_prices/developer/intro">Developer Guide</a><a href="https://jpawlowski.github.io/hass.tibber_prices/user/" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">User Docs<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><a class="navbar__item navbar__link" href="/hass.tibber_prices/developer/critical-patterns">Next 🚧</a><a href="https://github.com/jpawlowski/hass.tibber_prices" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="system mode" aria-label="Switch between dark and light mode (currently system mode)"><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP systemToggleIcon_QzmC"><path fill="currentColor" d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"></path></svg></button></div><div class="navbarSearchContainer_Bca1"><div class="navbar__search"><span aria-label="expand searchbar" role="button" class="search-icon" tabindex="0"></span><input id="search_input_react" type="search" placeholder="Loading..." aria-label="Search" class="navbar__search-input search-bar" disabled=""></div></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="theme-layout-main main-wrapper mainWrapper_z2l0"><div class="docsWrapper_hBAB"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docRoot_UBD9"><aside class="theme-doc-sidebar-container docSidebarContainer_YfHR"><div class="sidebarViewport_aRkj"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/hass.tibber_prices/developer/intro"><span title="Developer Documentation" class="linkLabel_WmDU">Developer Documentation</span></a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/architecture"><span title="🏗️ Architecture" class="categoryLinkLabel_W154">🏗️ Architecture</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/architecture"><span title="Architecture" class="linkLabel_WmDU">Architecture</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/timer-architecture"><span title="Timer Architecture" class="linkLabel_WmDU">Timer Architecture</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/caching-strategy"><span title="Caching Strategy" class="linkLabel_WmDU">Caching Strategy</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/api-reference"><span title="API Reference" class="linkLabel_WmDU">API Reference</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/setup"><span title="💻 Development" class="categoryLinkLabel_W154">💻 Development</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/setup"><span title="Development Setup" class="linkLabel_WmDU">Development Setup</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/coding-guidelines"><span title="Coding Guidelines" class="linkLabel_WmDU">Coding Guidelines</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/hass.tibber_prices/developer/critical-patterns"><span title="Critical Behavior Patterns - Testing Guide" class="linkLabel_WmDU">Critical Behavior Patterns - Testing Guide</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/debugging"><span title="Debugging Guide" class="linkLabel_WmDU">Debugging Guide</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/period-calculation-theory"><span title="📐 Advanced Topics" class="categoryLinkLabel_W154">📐 Advanced Topics</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/period-calculation-theory"><span title="Period Calculation Theory" class="linkLabel_WmDU">Period Calculation Theory</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/refactoring-guide"><span title="Refactoring Guide" class="linkLabel_WmDU">Refactoring Guide</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/performance"><span title="Performance Optimization" class="linkLabel_WmDU">Performance Optimization</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/contributing"><span title="📝 Contributing" class="categoryLinkLabel_W154">📝 Contributing</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/contributing"><span title="Contributing Guide" class="linkLabel_WmDU">Contributing Guide</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/release-management"><span title="🚀 Release" class="categoryLinkLabel_W154">🚀 Release</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/release-management"><span title="Release Notes Generation" class="linkLabel_WmDU">Release Notes Generation</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/testing"><span title="Testing" class="linkLabel_WmDU">Testing</span></a></li></ul></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_PEFL"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_kv0_"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></div></aside><main class="docMainContainer_TBSr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="theme-doc-version-banner alert alert--warning margin-bottom--md" role="alert"><div>This is unreleased documentation for <!-- -->Tibber Prices - Developer Guide<!-- --> <b>Next 🚧</b> version.</div><div class="margin-top--md">For up-to-date documentation, see the <b><a href="/hass.tibber_prices/developer/critical-patterns">latest version</a></b> (<!-- -->Next 🚧<!-- -->).</div></div><div class="docItemContainer_Djhp"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="Breadcrumbs"><ul class="breadcrumbs"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/hass.tibber_prices/developer/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YNFT"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">💻 Development</span></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">Critical Behavior Patterns - Testing Guide</span></li></ul></nav><span class="theme-doc-version-badge badge badge--secondary">Version: Next 🚧</span><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Critical Behavior Patterns - Testing Guide</h1></header>
<p><strong>Purpose:</strong> This documentation lists essential behavior patterns that must be tested to ensure production-quality code and prevent resource leaks.</p>
<p><strong>Last Updated:</strong> 2025-11-22
<strong>Test Coverage:</strong> 41 tests implemented (100% of critical patterns)</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-why-are-these-tests-critical">🎯 Why Are These Tests Critical?<a href="#-why-are-these-tests-critical" class="hash-link" aria-label="Direct link to 🎯 Why Are These Tests Critical?" title="Direct link to 🎯 Why Are These Tests Critical?" translate="no"></a></h2>
<p>Home Assistant integrations run <strong>continuously</strong> in the background. Resource leaks lead to:</p>
<ul>
<li class=""><strong>Memory Leaks</strong>: RAM usage grows over days/weeks until HA becomes unstable</li>
<li class=""><strong>Callback Leaks</strong>: Listeners remain registered after entity removal → CPU load increases</li>
<li class=""><strong>Timer Leaks</strong>: Timers continue running after unload → unnecessary background tasks</li>
<li class=""><strong>File Handle Leaks</strong>: Storage files remain open → system resources exhausted</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-test-categories">✅ Test Categories<a href="#-test-categories" class="hash-link" aria-label="Direct link to ✅ Test Categories" title="Direct link to ✅ Test Categories" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-resource-cleanup-memory-leak-prevention">1. Resource Cleanup (Memory Leak Prevention)<a href="#1-resource-cleanup-memory-leak-prevention" class="hash-link" aria-label="Direct link to 1. Resource Cleanup (Memory Leak Prevention)" title="Direct link to 1. Resource Cleanup (Memory Leak Prevention)" translate="no"></a></h3>
<p><strong>File:</strong> <code>tests/test_resource_cleanup.py</code></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-listener-cleanup-">1.1 Listener Cleanup ✅<a href="#11-listener-cleanup-" class="hash-link" aria-label="Direct link to 1.1 Listener Cleanup ✅" title="Direct link to 1.1 Listener Cleanup ✅" translate="no"></a></h4>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">Time-sensitive listeners are correctly removed (<code>async_add_time_sensitive_listener()</code>)</li>
<li class="">Minute-update listeners are correctly removed (<code>async_add_minute_update_listener()</code>)</li>
<li class="">Lifecycle callbacks are correctly unregistered (<code>register_lifecycle_callback()</code>)</li>
<li class="">Sensor cleanup removes ALL registered listeners</li>
<li class="">Binary sensor cleanup removes ALL registered listeners</li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class="">Each registered listener holds references to Entity + Coordinator</li>
<li class="">Without cleanup: Entities are not freed by GC → Memory Leak</li>
<li class="">With 80+ sensors × 3 listener types = 240+ callbacks that must be cleanly removed</li>
</ul>
<p><strong>Code Locations:</strong></p>
<ul>
<li class=""><code>coordinator/listeners.py</code><code>async_add_time_sensitive_listener()</code>, <code>async_add_minute_update_listener()</code></li>
<li class=""><code>coordinator/core.py</code><code>register_lifecycle_callback()</code></li>
<li class=""><code>sensor/core.py</code><code>async_will_remove_from_hass()</code></li>
<li class=""><code>binary_sensor/core.py</code><code>async_will_remove_from_hass()</code></li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-timer-cleanup-">1.2 Timer Cleanup ✅<a href="#12-timer-cleanup-" class="hash-link" aria-label="Direct link to 1.2 Timer Cleanup ✅" title="Direct link to 1.2 Timer Cleanup ✅" translate="no"></a></h4>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">Quarter-hour timer is cancelled and reference cleared</li>
<li class="">Minute timer is cancelled and reference cleared</li>
<li class="">Both timers are cancelled together</li>
<li class="">Cleanup works even when timers are <code>None</code></li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class="">Uncancelled timers continue running after integration unload</li>
<li class="">HA&#x27;s <code>async_track_utc_time_change()</code> creates persistent callbacks</li>
<li class="">Without cleanup: Timers keep firing → CPU load + unnecessary coordinator updates</li>
</ul>
<p><strong>Code Locations:</strong></p>
<ul>
<li class=""><code>coordinator/listeners.py</code><code>cancel_timers()</code></li>
<li class=""><code>coordinator/core.py</code><code>async_shutdown()</code></li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-config-entry-cleanup-">1.3 Config Entry Cleanup ✅<a href="#13-config-entry-cleanup-" class="hash-link" aria-label="Direct link to 1.3 Config Entry Cleanup ✅" title="Direct link to 1.3 Config Entry Cleanup ✅" translate="no"></a></h4>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">Options update listener is registered via <code>async_on_unload()</code></li>
<li class="">Cleanup function is correctly passed to <code>async_on_unload()</code></li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class=""><code>entry.add_update_listener()</code> registers permanent callback</li>
<li class="">Without <code>async_on_unload()</code>: Listener remains active after reload → duplicate updates</li>
<li class="">Pattern: <code>entry.async_on_unload(entry.add_update_listener(handler))</code></li>
</ul>
<p><strong>Code Locations:</strong></p>
<ul>
<li class=""><code>coordinator/core.py</code><code>__init__()</code> (listener registration)</li>
<li class=""><code>__init__.py</code><code>async_unload_entry()</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-cache-invalidation-">2. Cache Invalidation ✅<a href="#2-cache-invalidation-" class="hash-link" aria-label="Direct link to 2. Cache Invalidation ✅" title="Direct link to 2. Cache Invalidation ✅" translate="no"></a></h3>
<p><strong>File:</strong> <code>tests/test_resource_cleanup.py</code></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-config-cache-invalidation">2.1 Config Cache Invalidation<a href="#21-config-cache-invalidation" class="hash-link" aria-label="Direct link to 2.1 Config Cache Invalidation" title="Direct link to 2.1 Config Cache Invalidation" translate="no"></a></h4>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">DataTransformer config cache is invalidated on options change</li>
<li class="">PeriodCalculator config + period cache is invalidated</li>
<li class="">Trend calculator cache is cleared on coordinator update</li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class="">Stale config → Sensors use old user settings</li>
<li class="">Stale period cache → Incorrect best/peak price periods</li>
<li class="">Stale trend cache → Outdated trend analysis</li>
</ul>
<p><strong>Code Locations:</strong></p>
<ul>
<li class=""><code>coordinator/data_transformation.py</code><code>invalidate_config_cache()</code></li>
<li class=""><code>coordinator/periods.py</code><code>invalidate_config_cache()</code></li>
<li class=""><code>sensor/calculators/trend.py</code><code>clear_trend_cache()</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-storage-cleanup-">3. Storage Cleanup ✅<a href="#3-storage-cleanup-" class="hash-link" aria-label="Direct link to 3. Storage Cleanup ✅" title="Direct link to 3. Storage Cleanup ✅" translate="no"></a></h3>
<p><strong>File:</strong> <code>tests/test_resource_cleanup.py</code> + <code>tests/test_coordinator_shutdown.py</code></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-persistent-storage-removal">3.1 Persistent Storage Removal<a href="#31-persistent-storage-removal" class="hash-link" aria-label="Direct link to 3.1 Persistent Storage Removal" title="Direct link to 3.1 Persistent Storage Removal" translate="no"></a></h4>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">Storage file is deleted on config entry removal</li>
<li class="">Cache is saved on shutdown (no data loss)</li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class="">Without storage removal: Old files remain after uninstallation</li>
<li class="">Without cache save on shutdown: Data loss on HA restart</li>
<li class="">Storage path: <code>.storage/tibber_prices.{entry_id}</code></li>
</ul>
<p><strong>Code Locations:</strong></p>
<ul>
<li class=""><code>__init__.py</code><code>async_remove_entry()</code></li>
<li class=""><code>coordinator/core.py</code><code>async_shutdown()</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-timer-scheduling-">4. Timer Scheduling ✅<a href="#4-timer-scheduling-" class="hash-link" aria-label="Direct link to 4. Timer Scheduling ✅" title="Direct link to 4. Timer Scheduling ✅" translate="no"></a></h3>
<p><strong>File:</strong> <code>tests/test_timer_scheduling.py</code></p>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">Quarter-hour timer is registered with correct parameters</li>
<li class="">Minute timer is registered with correct parameters</li>
<li class="">Timers can be re-scheduled (override old timer)</li>
<li class="">Midnight turnover detection works correctly</li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class="">Wrong timer parameters → Entities update at wrong times</li>
<li class="">Without timer override on re-schedule → Multiple parallel timers → Performance problem</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-sensor-to-timer-assignment-">5. Sensor-to-Timer Assignment ✅<a href="#5-sensor-to-timer-assignment-" class="hash-link" aria-label="Direct link to 5. Sensor-to-Timer Assignment ✅" title="Direct link to 5. Sensor-to-Timer Assignment ✅" translate="no"></a></h3>
<p><strong>File:</strong> <code>tests/test_sensor_timer_assignment.py</code></p>
<p><strong>What is tested:</strong></p>
<ul>
<li class="">All <code>TIME_SENSITIVE_ENTITY_KEYS</code> are valid entity keys</li>
<li class="">All <code>MINUTE_UPDATE_ENTITY_KEYS</code> are valid entity keys</li>
<li class="">Both lists are disjoint (no overlap)</li>
<li class="">Sensor and binary sensor platforms are checked</li>
</ul>
<p><strong>Why critical:</strong></p>
<ul>
<li class="">Wrong timer assignment → Sensors update at wrong times</li>
<li class="">Overlap → Duplicate updates → Performance problem</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-additional-analysis-nice-to-have-patterns">🚨 Additional Analysis (Nice-to-Have Patterns)<a href="#-additional-analysis-nice-to-have-patterns" class="hash-link" aria-label="Direct link to 🚨 Additional Analysis (Nice-to-Have Patterns)" title="Direct link to 🚨 Additional Analysis (Nice-to-Have Patterns)" translate="no"></a></h2>
<p>These patterns were analyzed and classified as <strong>not critical</strong>:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-async-task-management">6. Async Task Management<a href="#6-async-task-management" class="hash-link" aria-label="Direct link to 6. Async Task Management" title="Direct link to 6. Async Task Management" translate="no"></a></h3>
<p><strong>Current Status:</strong> Fire-and-forget pattern for short tasks</p>
<ul>
<li class=""><code>sensor/core.py</code> → Chart data refresh (short-lived, max 1-2 seconds)</li>
<li class=""><code>coordinator/core.py</code> → Cache storage (short-lived, max 100ms)</li>
</ul>
<p><strong>Why no tests needed:</strong></p>
<ul>
<li class="">No long-running tasks (all &lt; 2 seconds)</li>
<li class="">HA&#x27;s event loop handles short tasks automatically</li>
<li class="">Task exceptions are already logged</li>
</ul>
<p><strong>If needed:</strong> <code>_chart_refresh_task</code> tracking + cancel in <code>async_will_remove_from_hass()</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-api-session-cleanup">7. API Session Cleanup<a href="#7-api-session-cleanup" class="hash-link" aria-label="Direct link to 7. API Session Cleanup" title="Direct link to 7. API Session Cleanup" translate="no"></a></h3>
<p><strong>Current Status:</strong> ✅ Correctly implemented</p>
<ul>
<li class=""><code>async_get_clientsession(hass)</code> is used (shared session)</li>
<li class="">No new sessions are created</li>
<li class="">HA manages session lifecycle automatically</li>
</ul>
<p><strong>Code:</strong> <code>api/client.py</code> + <code>__init__.py</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-translation-cache-memory">8. Translation Cache Memory<a href="#8-translation-cache-memory" class="hash-link" aria-label="Direct link to 8. Translation Cache Memory" title="Direct link to 8. Translation Cache Memory" translate="no"></a></h3>
<p><strong>Current Status:</strong> ✅ Bounded cache</p>
<ul>
<li class="">Max ~5-10 languages × 5KB = 50KB total</li>
<li class="">Module-level cache without re-loading</li>
<li class="">Practically no memory issue</li>
</ul>
<p><strong>Code:</strong> <code>const.py</code><code>_TRANSLATIONS_CACHE</code>, <code>_STANDARD_TRANSLATIONS_CACHE</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="9-coordinator-data-structure-integrity">9. Coordinator Data Structure Integrity<a href="#9-coordinator-data-structure-integrity" class="hash-link" aria-label="Direct link to 9. Coordinator Data Structure Integrity" title="Direct link to 9. Coordinator Data Structure Integrity" translate="no"></a></h3>
<p><strong>Current Status:</strong> Manually tested via <code>./scripts/develop</code></p>
<ul>
<li class="">Midnight turnover works correctly (observed over several days)</li>
<li class="">Missing keys are handled via <code>.get()</code> with defaults</li>
<li class="">80+ sensors access <code>coordinator.data</code> without errors</li>
</ul>
<p><strong>Structure:</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">coordinator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;user_data&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;priceInfo&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Flat list of all enriched intervals</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;currency&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;EUR&quot;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Top-level for easy access</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="10-service-response-memory">10. Service Response Memory<a href="#10-service-response-memory" class="hash-link" aria-label="Direct link to 10. Service Response Memory" title="Direct link to 10. Service Response Memory" translate="no"></a></h3>
<p><strong>Current Status:</strong> HA&#x27;s response lifecycle</p>
<ul>
<li class="">HA automatically frees service responses after return</li>
<li class="">ApexCharts ~20KB response is one-time per call</li>
<li class="">No response accumulation in integration code</li>
</ul>
<p><strong>Code:</strong> <code>services/apexcharts.py</code></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-test-coverage-status">📊 Test Coverage Status<a href="#-test-coverage-status" class="hash-link" aria-label="Direct link to 📊 Test Coverage Status" title="Direct link to 📊 Test Coverage Status" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="-implemented-tests-41-total">✅ Implemented Tests (41 total)<a href="#-implemented-tests-41-total" class="hash-link" aria-label="Direct link to ✅ Implemented Tests (41 total)" title="Direct link to ✅ Implemented Tests (41 total)" translate="no"></a></h3>
<table><thead><tr><th>Category</th><th>Status</th><th>Tests</th><th>File</th><th>Coverage</th></tr></thead><tbody><tr><td>Listener Cleanup</td><td></td><td>5</td><td><code>test_resource_cleanup.py</code></td><td>100%</td></tr><tr><td>Timer Cleanup</td><td></td><td>4</td><td><code>test_resource_cleanup.py</code></td><td>100%</td></tr><tr><td>Config Entry Cleanup</td><td></td><td>1</td><td><code>test_resource_cleanup.py</code></td><td>100%</td></tr><tr><td>Cache Invalidation</td><td></td><td>3</td><td><code>test_resource_cleanup.py</code></td><td>100%</td></tr><tr><td>Storage Cleanup</td><td></td><td>1</td><td><code>test_resource_cleanup.py</code></td><td>100%</td></tr><tr><td>Storage Persistence</td><td></td><td>2</td><td><code>test_coordinator_shutdown.py</code></td><td>100%</td></tr><tr><td>Timer Scheduling</td><td></td><td>8</td><td><code>test_timer_scheduling.py</code></td><td>100%</td></tr><tr><td>Sensor-Timer Assignment</td><td></td><td>17</td><td><code>test_sensor_timer_assignment.py</code></td><td>100%</td></tr><tr><td><strong>TOTAL</strong></td><td><strong></strong></td><td><strong>41</strong></td><td></td><td><strong>100% (critical)</strong></td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="-analyzed-but-not-implemented-nice-to-have">📋 Analyzed but Not Implemented (Nice-to-Have)<a href="#-analyzed-but-not-implemented-nice-to-have" class="hash-link" aria-label="Direct link to 📋 Analyzed but Not Implemented (Nice-to-Have)" title="Direct link to 📋 Analyzed but Not Implemented (Nice-to-Have)" translate="no"></a></h3>
<table><thead><tr><th>Category</th><th>Status</th><th>Rationale</th></tr></thead><tbody><tr><td>Async Task Management</td><td>📋</td><td>Fire-and-forget pattern used (no long-running tasks)</td></tr><tr><td>API Session Cleanup</td><td></td><td>Pattern correct (<code>async_get_clientsession</code> used)</td></tr><tr><td>Translation Cache</td><td></td><td>Cache size bounded (~50KB max for 10 languages)</td></tr><tr><td>Data Structure Integrity</td><td>📋</td><td>Would add test time without finding real issues</td></tr><tr><td>Service Response Memory</td><td>📋</td><td>HA automatically frees service responses</td></tr></tbody></table>
<p><strong>Legend:</strong></p>
<ul>
<li class="">✅ = Fully tested or pattern verified correct</li>
<li class="">📋 = Analyzed, low priority for testing (no known issues)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-development-status">🎯 Development Status<a href="#-development-status" class="hash-link" aria-label="Direct link to 🎯 Development Status" title="Direct link to 🎯 Development Status" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="-all-critical-patterns-tested">✅ All Critical Patterns Tested<a href="#-all-critical-patterns-tested" class="hash-link" aria-label="Direct link to ✅ All Critical Patterns Tested" title="Direct link to ✅ All Critical Patterns Tested" translate="no"></a></h3>
<p>All essential memory leak prevention patterns are covered by 41 tests:</p>
<ul>
<li class="">✅ Listeners are correctly removed (no callback leaks)</li>
<li class="">✅ Timers are cancelled (no background task leaks)</li>
<li class="">✅ Config entry cleanup works (no dangling listeners)</li>
<li class="">✅ Caches are invalidated (no stale data issues)</li>
<li class="">✅ Storage is saved and cleaned up (no data loss)</li>
<li class="">✅ Timer scheduling works correctly (no update issues)</li>
<li class="">✅ Sensor-timer assignment is correct (no wrong updates)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="-nice-to-have-tests-optional">📋 Nice-to-Have Tests (Optional)<a href="#-nice-to-have-tests-optional" class="hash-link" aria-label="Direct link to 📋 Nice-to-Have Tests (Optional)" title="Direct link to 📋 Nice-to-Have Tests (Optional)" translate="no"></a></h3>
<p>If problems arise in the future, these tests can be added:</p>
<ol>
<li class=""><strong>Async Task Management</strong> - Pattern analyzed (fire-and-forget for short tasks)</li>
<li class=""><strong>Data Structure Integrity</strong> - Midnight rotation manually tested</li>
<li class=""><strong>Service Response Memory</strong> - HA&#x27;s response lifecycle automatic</li>
</ol>
<p><strong>Conclusion:</strong> The integration has production-quality test coverage for all critical resource leak patterns.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-how-to-run-tests">🔍 How to Run Tests<a href="#-how-to-run-tests" class="hash-link" aria-label="Direct link to 🔍 How to Run Tests" title="Direct link to 🔍 How to Run Tests" translate="no"></a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Run all resource cleanup tests (14 tests)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./scripts/test tests/test_resource_cleanup.py </span><span class="token parameter variable" style="color:#36acaa">-v</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Run all critical pattern tests (41 tests)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./scripts/test tests/test_resource_cleanup.py tests/test_coordinator_shutdown.py </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> tests/test_timer_scheduling.py tests/test_sensor_timer_assignment.py </span><span class="token parameter variable" style="color:#36acaa">-v</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Run all tests with coverage</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./scripts/test </span><span class="token parameter variable" style="color:#36acaa">--cov</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">custom_components.tibber_prices --cov-report</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">html</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Type checking and linting</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./scripts/check</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Manual memory leak test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 1. Start HA: ./scripts/develop</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 2. Monitor RAM: watch -n 1 &#x27;ps aux | grep home-assistant&#x27;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 3. Reload integration multiple times (HA UI: Settings → Devices → Tibber Prices → Reload)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 4. RAM should stabilize (not grow continuously)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="-references">📚 References<a href="#-references" class="hash-link" aria-label="Direct link to 📚 References" title="Direct link to 📚 References" translate="no"></a></h2>
<ul>
<li class=""><strong>Home Assistant Cleanup Patterns</strong>: <a href="https://developers.home-assistant.io/docs/integration_setup_failures/#cleanup" target="_blank" rel="noopener noreferrer" class="">https://developers.home-assistant.io/docs/integration_setup_failures/#cleanup</a></li>
<li class=""><strong>Async Best Practices</strong>: <a href="https://developers.home-assistant.io/docs/asyncio_101/" target="_blank" rel="noopener noreferrer" class="">https://developers.home-assistant.io/docs/asyncio_101/</a></li>
<li class=""><strong>Memory Profiling</strong>: <a href="https://docs.python.org/3/library/tracemalloc.html" target="_blank" rel="noopener noreferrer" class="">https://docs.python.org/3/library/tracemalloc.html</a></li>
</ul></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="row margin-top--sm theme-doc-footer-edit-meta-row"><div class="col noPrint_WFHX"><a href="https://github.com/jpawlowski/hass.tibber_prices/tree/main/docs/developer/docs/critical-patterns.md" target="_blank" rel="noopener noreferrer" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_JAkA"><span class="theme-last-updated">Last updated<!-- --> on <b><time datetime="2025-12-06T01:37:06.000Z" itemprop="dateModified">Dec 6, 2025</time></b></span></div></div></footer></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/hass.tibber_prices/developer/coding-guidelines"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Coding Guidelines</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/hass.tibber_prices/developer/debugging"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Debugging Guide</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#-why-are-these-tests-critical" class="table-of-contents__link toc-highlight">🎯 Why Are These Tests Critical?</a></li><li><a href="#-test-categories" class="table-of-contents__link toc-highlight">✅ Test Categories</a><ul><li><a href="#1-resource-cleanup-memory-leak-prevention" class="table-of-contents__link toc-highlight">1. Resource Cleanup (Memory Leak Prevention)</a></li><li><a href="#2-cache-invalidation-" class="table-of-contents__link toc-highlight">2. Cache Invalidation ✅</a></li><li><a href="#3-storage-cleanup-" class="table-of-contents__link toc-highlight">3. Storage Cleanup ✅</a></li><li><a href="#4-timer-scheduling-" class="table-of-contents__link toc-highlight">4. Timer Scheduling ✅</a></li><li><a href="#5-sensor-to-timer-assignment-" class="table-of-contents__link toc-highlight">5. Sensor-to-Timer Assignment ✅</a></li></ul></li><li><a href="#-additional-analysis-nice-to-have-patterns" class="table-of-contents__link toc-highlight">🚨 Additional Analysis (Nice-to-Have Patterns)</a><ul><li><a href="#6-async-task-management" class="table-of-contents__link toc-highlight">6. Async Task Management</a></li><li><a href="#7-api-session-cleanup" class="table-of-contents__link toc-highlight">7. API Session Cleanup</a></li><li><a href="#8-translation-cache-memory" class="table-of-contents__link toc-highlight">8. Translation Cache Memory</a></li><li><a href="#9-coordinator-data-structure-integrity" class="table-of-contents__link toc-highlight">9. Coordinator Data Structure Integrity</a></li><li><a href="#10-service-response-memory" class="table-of-contents__link toc-highlight">10. Service Response Memory</a></li></ul></li><li><a href="#-test-coverage-status" class="table-of-contents__link toc-highlight">📊 Test Coverage Status</a><ul><li><a href="#-implemented-tests-41-total" class="table-of-contents__link toc-highlight">✅ Implemented Tests (41 total)</a></li><li><a href="#-analyzed-but-not-implemented-nice-to-have" class="table-of-contents__link toc-highlight">📋 Analyzed but Not Implemented (Nice-to-Have)</a></li></ul></li><li><a href="#-development-status" class="table-of-contents__link toc-highlight">🎯 Development Status</a><ul><li><a href="#-all-critical-patterns-tested" class="table-of-contents__link toc-highlight">✅ All Critical Patterns Tested</a></li><li><a href="#-nice-to-have-tests-optional" class="table-of-contents__link toc-highlight">📋 Nice-to-Have Tests (Optional)</a></li></ul></li><li><a href="#-how-to-run-tests" class="table-of-contents__link toc-highlight">🔍 How to Run Tests</a></li><li><a href="#-references" class="table-of-contents__link toc-highlight">📚 References</a></li></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Documentation</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://jpawlowski.github.io/hass.tibber_prices/user/" target="_blank" rel="noopener noreferrer" class="footer__link-item">User Guide<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a class="footer__link-item" href="/hass.tibber_prices/developer/intro">Developer Guide</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/jpawlowski/hass.tibber_prices/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub Issues<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://community.home-assistant.io/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Home Assistant Community<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">More</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/jpawlowski/hass.tibber_prices" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://github.com/jpawlowski/hass.tibber_prices/releases" target="_blank" rel="noopener noreferrer" class="footer__link-item">Release Notes<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Not affiliated with Tibber AS. Community-maintained custom integration. Built with Docusaurus.</div></div></div></footer></div>
</body>
</html>