Skip to content

Commit 5457ef0

Browse files
committed
testing: fix up various aspects that are breaking tests (bug 1887042)
- skip: test_auth, test_dockerflow, test_notifications, test_diff_warnings - skip parts of test_landing_job - remove test_health module (mostly deprecated) - remove test_py3_code_quality (already replaced elsewhere) - convert headers in tests from a list to a dict (bug 1887043) - use django test client in lieu of FlaskClient (bug 1887043) - remove disable_migrations fixture - remove celery_app fixture - temporarily comment out cache decorators - adapt app fixture to new platform - remove flask celery functionality - add base celery support - add boilerplate django celery implementation - add db to github workflow (postgres) - add rust toolchain - various fix ups to get tests to run - various other missed fixes - various additions to the settings module - consolidate migrations
1 parent 222b7b1 commit 5457ef0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+362
-461
lines changed

.github/workflows/build.yml

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@ on:
88
jobs:
99
run-tests:
1010
runs-on: ubuntu-latest
11+
services:
12+
postgres:
13+
image: postgres:latest
14+
env:
15+
POSTGRES_USER: postgres
16+
POSTGRES_PASSWORD: postgres
17+
ports:
18+
- 5432:5432
19+
options:
20+
--health-cmd pg_isready
21+
--health-interval 10s
22+
--health-timeout 5s
23+
--health-retries 5
1124
steps:
1225
- uses: actions/checkout@v4
1326
- name: Set up Python
@@ -22,7 +35,10 @@ jobs:
2235
python -m pip install -r requirements.txt
2336
python -m pip install -e .
2437
- name: Test
38+
env:
39+
DEFAULT_DB_HOST: 127.0.0.1
2540
run: |
2641
source env/bin/activate
42+
lando migrate
2743
lando test
28-
pytest
44+
pytest src/lando/api

Dockerfile

+11
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,20 @@ EXPOSE 80
44
ENV PYTHONUNBUFFERED=1
55
ENV PYTHONDONTWRITEBYTECODE 1
66
RUN adduser --system --no-create-home app
7+
78
RUN mkdir /code
89
COPY ./ /code
910
RUN pip install --upgrade pip
11+
12+
13+
# Install the Rust toolchain. Some packages do not have pre-built wheels (e.g.
14+
# rs-parsepatch) and require this in order to compile.
15+
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
16+
17+
# Include ~/.cargo/bin in PATH.
18+
# See: rust-lang.org/tools/install (Configuring the PATH environment variable).
19+
ENV PATH="/root/.cargo/bin:${PATH}"
20+
1021
RUN pip install -r /code/requirements.txt
1122
RUN pip install -e /code
1223
USER app

pyproject.toml

+3
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ build-backend = "setuptools.build_meta"
3232

3333
[tool.setuptools.packages.find]
3434
where = ["src"]
35+
36+
[tool.pytest.ini_options]
37+
DJANGO_SETTINGS_MODULE = "lando.settings"

requirements.txt

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
black
22
jinja2
3+
kombu
34
pytest
45
pytest-django
6+
python-hglib==2.6.2
7+
python-jose
8+
redis
9+
requests-mock
510
ruff
611
uwsgi
12+
celery
13+
datadog
14+
rs-parsepatch
15+
networkx

src/lando/api/legacy/api/diff_warnings.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111

1212
import logging
1313

14-
from lando.main.support import problem
15-
1614
from lando.api.legacy.decorators import require_phabricator_api_key
1715
from lando.main.models.revision import DiffWarning, DiffWarningStatus
16+
from lando.main.support import problem
1817

1918
logger = logging.getLogger(__name__)
2019

src/lando/api/legacy/api/landing_jobs.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44
import logging
55

6-
from lando.main.support import ProblemException, g
7-
86
from lando.api import auth
97
from lando.main.models.landing_job import LandingJob, LandingJobAction, LandingJobStatus
8+
from lando.main.support import ProblemException, g
109

1110
logger = logging.getLogger(__name__)
1211

src/lando/api/legacy/api/stacks.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44
import logging
55
import urllib.parse
66

7-
from lando.main.support import problem
87
from lando import settings
9-
108
from lando.api.legacy.commit_message import format_commit_message
119
from lando.api.legacy.decorators import require_phabricator_api_key
12-
from lando.main.models.revision import Revision
1310
from lando.api.legacy.phabricator import PhabricatorClient
1411
from lando.api.legacy.projects import (
1512
get_release_managers,
@@ -42,6 +39,8 @@
4239
from lando.api.legacy.transplants import get_blocker_checks
4340
from lando.api.legacy.users import user_search
4441
from lando.api.legacy.validation import revision_id_to_int
42+
from lando.main.models.revision import Revision
43+
from lando.main.support import problem
4544

4645
logger = logging.getLogger(__name__)
4746

src/lando/api/legacy/api/transplants.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,11 @@
77
from typing import Optional
88

99
import kombu
10-
from lando.main.support import ProblemException, problem, g
11-
from lando import settings
1210

13-
from lando.api import auth
11+
from lando import settings
12+
from lando.api.legacy import auth
1413
from lando.api.legacy.commit_message import format_commit_message
1514
from lando.api.legacy.decorators import require_phabricator_api_key
16-
from lando.main.models.landing_job import (
17-
LandingJob,
18-
LandingJobStatus,
19-
add_revisions_to_job,
20-
)
21-
from lando.main.models.revision import Revision
2215
from lando.api.legacy.phabricator import PhabricatorClient
2316
from lando.api.legacy.projects import (
2417
CHECKIN_PROJ_SLUG,
@@ -67,6 +60,13 @@
6760
parse_landing_path,
6861
revision_id_to_int,
6962
)
63+
from lando.main.models.landing_job import (
64+
LandingJob,
65+
LandingJobStatus,
66+
add_revisions_to_job,
67+
)
68+
from lando.main.models.revision import Revision
69+
from lando.main.support import ProblemException, g, problem
7070

7171
logger = logging.getLogger(__name__)
7272

src/lando/api/legacy/api/try_push.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@
88
import io
99
import logging
1010

11-
from lando.main.support import ProblemException, g
12-
11+
from lando import settings
1312
from lando.api import auth
1413
from lando.api.legacy.hgexports import (
1514
GitPatchHelper,
1615
HgPatchHelper,
1716
PatchHelper,
1817
)
18+
from lando.api.legacy.repos import (
19+
get_repos_for_env,
20+
)
1921
from lando.main.models.landing_job import (
2022
LandingJobStatus,
2123
add_job_with_revisions,
2224
)
2325
from lando.main.models.revision import Revision
24-
from lando.api.legacy.repos import (
25-
get_repos_for_env,
26-
)
26+
from lando.main.support import ProblemException, g
2727

2828
logger = logging.getLogger(__name__)
2929

src/lando/api/legacy/api/uplift.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
import logging
66

7-
from lando.main.support import problem
87
from lando import settings
9-
108
from lando.api import auth
119
from lando.api.legacy.decorators import require_phabricator_api_key
1210
from lando.api.legacy.phabricator import PhabricatorClient
@@ -18,6 +16,7 @@
1816
get_uplift_repositories,
1917
)
2018
from lando.api.legacy.validation import revision_id_to_int
19+
from lando.main.support import problem
2120

2221
logger = logging.getLogger(__name__)
2322

src/lando/api/legacy/app.py

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import connexion
1010
from connexion.resolver import RestyResolver
1111

12-
import landoapi.models # noqa, makes sure alembic knows about the models.
1312
from lando.api.legacy.auth import auth0_subsystem
1413
from lando.api.legacy.cache import cache_subsystem
1514
from lando.api.legacy.celery import celery_subsystem

src/lando/api/legacy/auth.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@
1515
)
1616

1717
import requests
18-
from lando.main.support import ProblemException, request
19-
from lando import settings
20-
from lando.main.support import g
18+
from django.core.cache import cache
2119
from jose import jwt
2220

23-
from django.core.cache import cache
21+
from lando import settings
2422
from lando.api.legacy.mocks.auth import MockAuth0
2523
from lando.api.legacy.repos import AccessGroup
2624
from lando.api.legacy.systems import Subsystem
25+
from lando.main.support import ProblemException, g, request
2726

2827
logger = logging.getLogger(__name__)
2928

@@ -32,7 +31,7 @@
3231

3332

3433
def get_auth_token() -> str:
35-
auth = request.headers.get("Authorization")
34+
auth = request["headers"].get("Authorization")
3635
if auth is None:
3736
raise ProblemException(
3837
401,

src/lando/api/legacy/bmo.py

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
import requests
6+
67
from lando import settings
78

89

src/lando/api/legacy/cache.py

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from flask_caching.backends.rediscache import RedisCache
1111
from redis import RedisError
1212

13+
from lando import settings
1314
from lando.api.legacy.redis import SuppressRedisFailure
1415
from lando.api.legacy.systems import Subsystem
1516

src/lando/api/legacy/celery.py

+12-101
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44
import logging
5+
import os
56

6-
import flask
77
from celery import Celery
88
from celery.signals import (
99
after_task_publish,
@@ -15,87 +15,24 @@
1515
)
1616
from datadog import statsd
1717

18-
from lando.api.legacy.systems import Subsystem
19-
2018
logger = logging.getLogger(__name__)
2119

2220

23-
class FlaskCelery(Celery):
24-
"""Celery which executes task in a flask app context."""
25-
26-
def __init__(self, *args, **kwargs):
27-
# Avoid passing the flask app to base Celery.
28-
flask_app = kwargs.pop("app", None)
29-
30-
super().__init__(*args, **kwargs)
31-
32-
# Important to run this after __init__ since task_cls
33-
# argument to base Celery can change what we're basing on.
34-
self._flask_override_task_class()
35-
36-
if flask_app is not None:
37-
self.init_app(flask_app)
38-
39-
@property
40-
def dispatch_disabled(self):
41-
"""Will the Celery job system dispatch tasks to the workers?"""
42-
return bool(self.app.config.get("DISABLE_CELERY"))
43-
44-
def init_app(self, app, config=None):
45-
"""Initialize with a flask app."""
46-
self.app = app
47-
48-
config = config or {}
49-
self.conf.update(main=app.import_name, **config)
50-
51-
if self.dispatch_disabled:
52-
logger.warning(
53-
"DISABLE_CELERY application configuration variable set, the Celery job "
54-
"system has been disabled! Any features that depend on the job system "
55-
"will not function."
56-
)
57-
58-
def _flask_override_task_class(self):
59-
"""Change Task class to one which executes in a flask context."""
60-
# Define a Task subclass that saves a reference to self in the Task object so
61-
# the task object can find self.app (the Flask application object) even if
62-
# self.app hasn't been set yet.
63-
#
64-
# We need to delay all of the task's calls to self.app using a custom Task class
65-
# because the reference to self.app may not be valid at the time the Celery
66-
# application object creates it set of Task objects. The programmer may
67-
# set self.app via the self.init_app() method at any time in the future.
68-
#
69-
# self.app is expected to be valid and usable by Task objects after the web
70-
# application is fully initialized and ready to serve requests.
71-
BaseTask = self.Task
72-
celery_self = self
73-
74-
class FlaskTask(BaseTask):
75-
"""A Celery Task subclass that has a reference to a Flask app."""
21+
# Set the default Django settings module for the 'celery' program.
22+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lando.settings')
7623

77-
def __call__(self, *args, **kwargs):
78-
# Override immediate calling of tasks, such as mytask(). This call
79-
# method is used by the Celery worker process.
80-
if flask.has_app_context():
81-
return super().__call__(*args, **kwargs)
24+
app = Celery('lando')
8225

83-
with celery_self.app.app_context():
84-
return super().__call__(*args, **kwargs)
26+
# Using a string here means the worker doesn't have to serialize
27+
# the configuration object to child processes.
28+
# - namespace='CELERY' means all celery-related configuration keys
29+
# should have a `CELERY_` prefix.
30+
app.config_from_object('django.conf:settings', namespace='CELERY')
8531

86-
def apply_async(self, *args, **kwargs):
87-
# Override delayed calling of tasks, such as mytask.apply_async().
88-
# This call method is used by the Celery app when it wants to
89-
# schedule a job for eventual execution on a worker.
90-
if celery_self.dispatch_disabled:
91-
return None
92-
else:
93-
return super().apply_async(*args, **kwargs)
32+
# Load task modules from all registered Django apps.
33+
app.autodiscover_tasks()
9434

95-
self.Task = FlaskTask
96-
97-
98-
celery = FlaskCelery()
35+
celery = app
9936

10037

10138
@after_task_publish.connect
@@ -129,29 +66,3 @@ def count_task_retried(**kwargs):
12966
def setup_celery_logging(**kwargs):
13067
# Prevent celery from overriding our logging configuration.
13168
pass
132-
133-
134-
class CelerySubsystem(Subsystem):
135-
name = "celery"
136-
137-
def init_app(self, app):
138-
super().init_app(app)
139-
140-
# Import tasks to discover celery tasks.
141-
import landoapi.tasks # noqa
142-
143-
celery.init_app(
144-
self.flask_app,
145-
config={"broker_url": settings.CELERY_BROKER_URL},
146-
)
147-
celery.log.setup()
148-
149-
def ready(self):
150-
if settings.DISABLE_CELERY:
151-
return True
152-
153-
# TODO: Check connection to CELERY_BROKER_URL
154-
return True
155-
156-
157-
celery_subsystem = CelerySubsystem()

0 commit comments

Comments
 (0)