Skip to content

Commit 388480d

Browse files
committed
Fix unit test failures on CS10 CI image
The test_async_pull_through_add test needed transaction=True because sync_to_async runs on a thread pool worker with a separate DB connection that can't see the main thread's uncommitted savepoint data. Using TransactionTestCase exposed two additional issues: - The base Repository has CONTENT_TYPES = [], so the task failed with "unsupported content types". Patch CONTENT_TYPES on the class so the re-fetched repo instance in the task also sees it. - TransactionTestCase teardown calls flush which emits post_migrate signals, but Django's emit_post_migrate_signal doesn't pass the `apps` kwarg. Made all four post_migrate handlers accept apps=None with a fallback to django.apps.apps. - After flush, the global default_domain cache is stale (old PK no longer in DB). Clear it in _ensure_default_domain so the domain is re-created, preventing FK violations in subsequent handlers. Also mock redis_tasks.async_are_resources_available for runners that use WORKER_TYPE=redis, where the dispatch path bypasses the postgres advisory lock code entirely and tries to connect to Redis. Assisted-By: Claude Opus 4.6
1 parent 6a88818 commit 388480d

3 files changed

Lines changed: 32 additions & 5 deletions

File tree

.github/workflows/scripts/install.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ fi
7070
cmd_prefix bash -c "echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/nopasswd"
7171
cmd_prefix bash -c "usermod -a -G wheel pulp"
7272

73+
# Workaround: Valkey on CS10 needs runtime directories that systemd-tmpfiles would create.
74+
# Remove once the CI image is rebuilt with these directories baked in.
75+
cmd_prefix bash -c "install -d -m 0755 -o valkey -g valkey /run/valkey && install -d -m 0750 -o valkey -g valkey /var/log/valkey && s6-rc -u change redis" || true
76+
7377
# In some scenarios we want to simulate a failed redis cache.
7478
if [[ " s3 " =~ " ${TEST} " ]]; then
7579
cmd_prefix bash -c "s6-rc -d change redis"

pulpcore/app/apps.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,11 @@ def _clean_app_status(sender, apps, verbosity, **kwargs):
275275
AppStatus.objects.filter(last_heartbeat__lt=TransactionNow() - F("ttl")).delete()
276276

277277

278-
def _populate_access_policies(sender, apps, verbosity, **kwargs):
278+
def _populate_access_policies(sender, apps=None, verbosity=0, **kwargs):
279+
from django.apps import apps as django_apps
280+
281+
if apps is None:
282+
apps = django_apps
279283
from pulpcore.app.util import get_view_urlpattern
280284
from pulpcore.app.viewsets import LoginViewSet
281285

@@ -319,7 +323,11 @@ def _populate_access_policies(sender, apps, verbosity, **kwargs):
319323
)
320324

321325

322-
def _populate_system_id(sender, apps, verbosity, **kwargs):
326+
def _populate_system_id(sender, apps=None, verbosity=0, **kwargs):
327+
from django.apps import apps as django_apps
328+
329+
if apps is None:
330+
apps = django_apps
323331
SystemID = apps.get_model("core", "SystemID")
324332
if not SystemID.objects.exists():
325333
SystemID().save()
@@ -328,8 +336,10 @@ def _populate_system_id(sender, apps, verbosity, **kwargs):
328336
def _ensure_default_domain(sender, **kwargs):
329337
table_names = connection.introspection.table_names()
330338
if "core_domain" in table_names:
339+
import pulpcore.app.util
331340
from pulpcore.app.util import get_default_domain
332341

342+
pulpcore.app.util.default_domain = None
333343
default = get_default_domain() # Cache the default domain
334344
# Match the Pulp settings
335345
if (
@@ -343,7 +353,11 @@ def _ensure_default_domain(sender, **kwargs):
343353
default.save(skip_hooks=True)
344354

345355

346-
def _populate_roles(sender, apps, verbosity, **kwargs):
356+
def _populate_roles(sender, apps=None, verbosity=0, **kwargs):
357+
from django.apps import apps as django_apps
358+
359+
if apps is None:
360+
apps = django_apps
347361
role_prefix = f"{sender.label}."
348362
# collect all plugin defined roles
349363
desired_roles = {}
@@ -402,7 +416,11 @@ def _get_permission(perm):
402416
role.permissions.set(permissions)
403417

404418

405-
def _populate_artifact_serving_distribution(sender, apps, verbosity, **kwargs):
419+
def _populate_artifact_serving_distribution(sender, apps=None, verbosity=0, **kwargs):
420+
from django.apps import apps as django_apps
421+
422+
if apps is None:
423+
apps = django_apps
406424
if (
407425
settings.STORAGES["default"]["BACKEND"] == "pulpcore.app.models.storage.FileSystem"
408426
or not settings.REDIRECT_TO_OBJECT_STORAGE

pulpcore/tests/unit/content/test_handler.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,15 +575,20 @@ async def test_app_status_fixture_is_reusable(app_status, repeat):
575575

576576

577577
@pytest.mark.asyncio
578-
@pytest.mark.django_db
578+
@pytest.mark.django_db(transaction=True)
579579
async def test_async_pull_through_add(ca1, monkeypatch, app_status):
580580
set_guid(uuid.uuid4()) # required for creating a task, no easily mockable
581581
monkeypatch.setattr(
582582
"pulpcore.tasking.tasks.async_are_resources_available", AsyncMock(return_value=True)
583583
)
584584
monkeypatch.setattr("pulpcore.tasking.tasks.wakeup_worker", Mock())
585+
monkeypatch.setattr(
586+
"pulpcore.tasking.redis_tasks.async_are_resources_available",
587+
AsyncMock(return_value=True),
588+
)
585589

586590
repo = await Repository.objects.acreate(name=str(uuid.uuid4()))
591+
monkeypatch.setattr(Repository, "CONTENT_TYPES", [Content])
587592
try:
588593
task = await repo.async_pull_through_add_content(ca1)
589594
assert task.state == TASK_STATES.COMPLETED

0 commit comments

Comments
 (0)