From 8a7caa51fdab7bdde19068cd259d9dc946d13852 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 23:11:20 +0000 Subject: [PATCH] fix(tests): keep live_download out of the default suite; stop org re-crawl on warm-cache miss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes that turn the e2e workflow green on main (run #47 failed on both attempts): - test_helper.exs: :live_download was never in the default ExUnit exclusion list — it was only ever kept out of 'mix test' by riding on the :external_api tag. Removing that tag in #68 therefore leaked the ~10-50MB download tests into the default suite, where they fail on runners without nickel ({:nickel_not_installed, "zig"}). Exclude :live_download explicitly; run them via --include live_download. - HyperpPolymathForge.fetch_package/2: a per-name cache miss triggered a full GitHub org re-crawl even when the index was already populated, so any absent package name burned unauthenticated rate limit and surfaced {:http_error, 401/403} instead of :not_found (the ETS-seeded 'no network fallback' test documents the intended contract, and CI runners hit this deterministically). A miss against a warm cache now returns :not_found without touching the network; a cold cache still refreshes and still propagates refresh errors. Warmth criterion mirrors ensure_index/0. Verified on OTP 28.3.1 / Elixir 1.19.5 — all three CI test commands green locally: full default suite 807 tests 0 failures, e2e step 55/55, runtime-api step 9/9 (6 excluded); compile --warnings-as-errors clean. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Kq24sZCEohSrNFXSuEuz6C --- .../opsm/registries/hyperpolymath_forge.ex | 25 +++++++++++++++---- opsm_ex/test/test_helper.exs | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/opsm_ex/lib/opsm/registries/hyperpolymath_forge.ex b/opsm_ex/lib/opsm/registries/hyperpolymath_forge.ex index a6604fa5..19776a75 100644 --- a/opsm_ex/lib/opsm/registries/hyperpolymath_forge.ex +++ b/opsm_ex/lib/opsm/registries/hyperpolymath_forge.ex @@ -71,7 +71,11 @@ defmodule Opsm.Registries.HyperpPolymathForge do Fetch a package from the Hyperpolymath Forge Registry. The package name must match the `[package] name` field in `opsm.toml`. - On cache miss, refreshes the full org index before looking up. + On cache miss with a cold (empty) index, refreshes the full org index + before looking up. A miss against a warm index returns `:not_found` + without touching the network — re-crawling the GitHub org for every + unknown name burns unauthenticated rate limit (CI runners get 403s, + surfacing as spurious `{:http_error, _}` instead of `:not_found`). ## Examples @@ -84,10 +88,14 @@ defmodule Opsm.Registries.HyperpPolymathForge do resolve_package(pkg_info, version) :miss -> - with :ok <- refresh_index() do - case lookup_cached(name) do - {:hit, pkg_info} -> resolve_package(pkg_info, version) - :miss -> {:error, :not_found} + if cache_warm?() do + {:error, :not_found} + else + with :ok <- refresh_index() do + case lookup_cached(name) do + {:hit, pkg_info} -> resolve_package(pkg_info, version) + :miss -> {:error, :not_found} + end end end end @@ -297,6 +305,13 @@ defmodule Opsm.Registries.HyperpPolymathForge do # Cache helpers # --------------------------------------------------------------------------- + # Same warmth criterion as ensure_index/0: a non-empty cache is the + # populated org index (expired entries are purged lazily by lookups). + defp cache_warm? do + ensure_cache() + :ets.info(@cache_table, :size) > 0 + end + defp lookup_cached(name) do ensure_cache() now = System.monotonic_time(:millisecond) diff --git a/opsm_ex/test/test_helper.exs b/opsm_ex/test/test_helper.exs index 16272192..fe60db6b 100644 --- a/opsm_ex/test/test_helper.exs +++ b/opsm_ex/test/test_helper.exs @@ -1,3 +1,3 @@ # SPDX-License-Identifier: MPL-2.0 # Copyright (c) Jonathan D.A. Jewell -ExUnit.start(exclude: [:e2e, :external_api, :requires_nif, :live_service]) +ExUnit.start(exclude: [:e2e, :external_api, :requires_nif, :live_service, :live_download])