Design: invalidate fixture cache when source definition changes
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 30/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Necesita aclaración
- Estado de actividad
- Activo
- Área
- backend, databases, performance
Línea de trabajo
Empieza leyendo Cache, FileCache, Fixture y Runner; después, sigue cómo Fixture#generate y Cache#exists? deciden si se reutilizan los datos del disco. Revisa #61 para conocer la ruta de carga diferida que dejó al descubierto el problema. Se considerará completado cuando haya acuerdo con los mantenedores sobre la huella digital de la caché, la ubicación de los metadatos, el comportamiento ante discrepancias y la estrategia de compatibilidad con versiones anteriores antes de la implementación.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Context
PR #61 fixed a NoMethodError when child fixtures were saved against a parent whose cache existed on disk but was not mounted in the current process. During review, a reviewer surfaced a deeper, pre-existing concern:
The lazy-load path can silently use stale parent cache data when the parent cache file exists but does not match the current parent fixture definition.
Fixture#generateskips regeneration when@cache.exists? && !force, andCache#exists?treats a disk file as sufficient. The new child-save path reads parent data directly from that file, andActiveRecordCoder#generatemergesparent_data.keysinto the captured model set. No definition digest, mtime check, schema/version key, or parent-definition validation was found inCache,FileCache,Fixture, orRunner.
This was deliberately scoped out of #61 because it is not new behavior — but it is a real correctness gap and warrants a separate design discussion.
Today's behavior
A fixture cache on disk is treated as valid forever, regardless of:
- Changes to the fixture's
Definitionblock in source code. - Changes to the underlying schema (new columns, dropped tables, type changes).
- Changes to
Codersubclasses (new coders registered, customencode/decodeupdated). - Changes to the Rails / Ruby version that wrote the cache.
The only safety nets today are:
- FK verification at mount time (
ActiveRecord.verify_foreign_keys_for_fixtures), which only catches a subset of schema drift and only at load. - Manual
FIXTURE_KIT_PRESERVE_CACHEopt-out anddb:test:prepare.
What needs deciding
1. What identifies a "valid" cache?
Candidates:
- Source digest of the
Definitionblock (and any procs it closes over — likely needsRubyVM::InstructionSequenceor source-location-based hashing). - mtime of the fixture file that declared the fixture. Cheaper, more brittle (touching the file invalidates).
- Schema fingerprint (digest of
db/schema.rb, orActiveRecord::Migration.current_version). - Coder fingerprint (registered coder classes + their source digest).
- FixtureKit version string (cheap, catches gem upgrades).
A useful cache fingerprint is probably a tuple of several of these, not one. The cheapest worthwhile combo is (fixture_kit_version, schema_version).
2. Where does the metadata live?
- New top-level key in the cache JSON (
"meta": { "version": ..., "schema": ..., "definition_digest": ... }). Simple, requires migrating existing caches. - Sidecar
.meta.jsonfile. Avoids touching the existing format. More disk I/O. - Filename suffix (
fixture.json.v2.abc123.json). Visible but ugly.
3. What happens on mismatch?
- Raise with a clear message ("cache version mismatch — regenerate"). Conservative.
- Silently regenerate. Convenient but hides bugs in the fingerprint logic.
- Warn + regenerate. Probably the right middle ground; logging is cheap.
4. Backward compatibility
Existing users have a populated cache directory. Options:
- Treat a cache without a
metablock as version-0 and force regeneration. One-time cost per fixture, no manual migration needed. - Add a CLI / rake task to migrate caches in place.
- Bump major version of the gem and document the cache reset as a breaking change.
Out of scope
- Auto-regeneration logic itself.
Fixture#generate(force:)already exists; this issue is about when to setforce: trueautomatically. - Cross-process locking. Worth tracking but separate.
Why this is filed as a discussion, not a PR
Each of the four questions above has reasonable answers in multiple directions, and the choices interact (a heavier fingerprint is more correct but more expensive; mismatch behavior is shaped by how cheap regeneration is in practice). Picking a strategy unilaterally and shipping a PR risks landing the wrong tradeoff. Looking for maintainer steer on at least Q1 and Q3 before coding.
Related
- #61 — fix for the lazy-load case that surfaced this concern
- #62 — follow-up: wrap corrupt cache errors (also from #61 review)
- Lenguaje dominante
- Ruby
- Estrellas
- 181
- Forks
- 4
- Merge medio
- 10 d 11 h
- PR fusionados (30 d)
- 1
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Gusto/fixture_kit
-
Clarify cache behavior with parallel test processesPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Gusto/fixture_kit#80 · 3 comentarios ·
Todos los issues de Gusto/fixture_kit
Issues similares
-
intercepted.rb crashes on an optional positional argument when the method also takes keywordsAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
yegor256/intercepted#128 ·
-
documentation good first issue
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
ysb3996-blip/oops#51 ·
Los mantenedores suelen responder en 1 día
-
good first issue
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
Remove leftover Cloud66 custom_web process from ProcfilePosiblemente ocupada @ShahadatTest la tomó hoy. AbiertoDifficulty: Easy Good First Issue
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
rubyforgood/casa#7330 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
area:core-lib P2 size:S
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día