@@ -0,0 +1,83 @@
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.sources.models import Source, SourceLease
|
||||
from apps.sources.services.scheduling import (
|
||||
acquire_source_lease,
|
||||
calculate_failure_backoff_seconds,
|
||||
release_source_lease,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_source_lease_blocks_concurrent_workers_and_recovers_when_expired(source):
|
||||
now = timezone.now()
|
||||
lease_a = acquire_source_lease(source_id=source.pk, worker_token="worker-a", now=now)
|
||||
assert lease_a is not None
|
||||
assert acquire_source_lease(source_id=source.pk, worker_token="worker-b", now=now) is None
|
||||
|
||||
assert release_source_lease(source_id=source.pk, worker_token="worker-a", now=now)
|
||||
lease_b = acquire_source_lease(source_id=source.pk, worker_token="worker-b", now=timezone.now())
|
||||
assert lease_b is not None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_source_lease_reuses_expired_lease(db, source):
|
||||
now = timezone.now()
|
||||
SourceLease.objects.create(
|
||||
source=source,
|
||||
token="expired-worker",
|
||||
worker_id="expired-worker",
|
||||
expires_at=now - timedelta(minutes=1),
|
||||
)
|
||||
lease = acquire_source_lease(source_id=source.pk, worker_token="recovery-worker", now=now)
|
||||
assert lease is not None
|
||||
assert lease.worker_id == "recovery-worker"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_source_lease_allows_origin_concurrency(db):
|
||||
shared_domain = "shared.example.org"
|
||||
source_a = Source.objects.create(
|
||||
name="Source A",
|
||||
source_type=Source.Type.EMPLOYER,
|
||||
base_url="https://shared.example.org/jobs/",
|
||||
domain=shared_domain,
|
||||
status=Source.Status.ACTIVE,
|
||||
policy=Source.Policy.ALLOW,
|
||||
max_concurrency=2,
|
||||
)
|
||||
source_b = Source.objects.create(
|
||||
name="Source B",
|
||||
source_type=Source.Type.EMPLOYER,
|
||||
base_url="https://shared.example.org/careers/",
|
||||
domain=shared_domain,
|
||||
status=Source.Status.ACTIVE,
|
||||
policy=Source.Policy.ALLOW,
|
||||
max_concurrency=2,
|
||||
)
|
||||
now = timezone.now()
|
||||
lease_a = acquire_source_lease(source_id=source_a.pk, worker_token="worker-a", now=now)
|
||||
lease_b = acquire_source_lease(source_id=source_b.pk, worker_token="worker-b", now=now)
|
||||
assert lease_a is not None
|
||||
assert lease_b is not None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_failure_backoff_uses_retry_after_and_bounds():
|
||||
source = Source(
|
||||
name="Temp",
|
||||
source_type=Source.Type.EMPLOYER,
|
||||
base_url="https://retry.example.org/",
|
||||
domain="retry.example.org",
|
||||
status=Source.Status.ACTIVE,
|
||||
policy=Source.Policy.ALLOW,
|
||||
)
|
||||
source.save()
|
||||
backoff = calculate_failure_backoff_seconds(
|
||||
source, failure_count=2, retry_after_seconds=120
|
||||
)
|
||||
assert backoff >= 120
|
||||
assert backoff <= 3600 + 45
|
||||
Reference in New Issue
Block a user