ScriptFileForm only validated uploaded scripts, so a script added by
selecting a data file bypassed validate_script_content. A script that
failed to load was committed as a broken module that showed as missing
and could not be corrected, since re-adding it tripped the file path
uniqueness constraint.
Validate the data file's content in the form's clean() the same way
uploaded files are validated, so a script that cannot be loaded is
rejected before any module is created.
When no ConfigRevision exists, the empty state was never cached, so every
request re-queried core_configrevision. Distinguish a genuine cache miss from
a cached-empty state via a sentinel, seed the empty state on first load, and
only consult the database on a true miss.
Treat the cache as warm only when both 'config' and 'config_version' are
present. A missing 'config_version' (evicted or never written) now re-queries
the database instead of leaving Config.version as None when a ConfigRevision
exists. The no-revision branch writes both keys, so the intentional empty
state remains a cache hit.
The config tests shared a single Redis instance (keyed only by a static
prefix) across parallel test workers, so a no-revision test in one worker
could seed empty config/config_version keys that another worker's test then
read, causing intermittent failures. Use a per-process LocMemCache so the
shared cache keys cannot be contaminated across workers.
Add RQQueueTestMixin to centralize RQ queue cleanup for test cases that
interact with background jobs. The mixin clears all RQ queues in setUp()
and tearDown(), preventing jobs created by one test from leaking into
later unrelated test runs.
Replace duplicate queue cleanup logic in core and netbox tests with the
shared mixin for better maintainability.
Fixes#22318
Rename `CablePathTestCase` to `BaseCablePathTestCase` and
`JobRunnerTestCase` to `BaseJobRunnerTestCase` to clearly indicate
their role as abstract base classes rather than concrete test cases.
Fixes#22338
CHOICE_SETS values (IATA, ISO_3166, UN_LOCODE) are lists of (value, label)
tuples, not dicts. The .values() call introduced by #21984 treated them as
dicts, raising AttributeError: 'list' object has no attribute 'values' when
full_clean() was invoked during choice set creation.
Replace with a generator expression that extracts the first element from
each tuple, matching the same pattern used elsewhere in the same model.
Also covers the save() path when order_alphabetically=True but
extra_choices is None (base-only choice set), preventing a TypeError
when sorted() receives None.
Replace manual `clear_config()` and `cache.clear()` calls at test end
with `addCleanup()` registered in `setUp()`. Ensures cleanup runs even
if assertions fail mid-test, preventing Redis pollution across tests.
Fixes#22290
Change action_object_type field in EventRuleFilter from StrFilterLookup
to ContentTypeFilter for proper content type filtering in GraphQL API.
Fixes#22287
Add tearDown method to empty the default queue after each test. Prevents
leftover jobs from leaking into later test suites that may reuse
the same queue instance.
Fixes#22319
Address review feedback on #22253:
- Registry stores resolvers as {app_label: resolver} dict instead of a
flat list, so each app can only register a resolver for its own models.
- register_serializer_resolver() now takes (app_label, resolver) and
get_serializer_for_model() only consults the resolver registered for
the model's own app.
- Remove 'serializer_resolver' from DEFAULT_RESOURCE_PATHS so this niche
resource is loaded only when a plugin explicitly defines it. The
PluginConfig.ready() path imports the configured path directly and
registers it under self.label.
- Update tests for the new per-app scoping; verify a resolver registered
for one app does not affect lookups in another.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>