Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage and check dependencies #589

Merged
merged 7 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
cd /app/src || exit

# Activate venv
. /app/venv/bin/activate
. /opt/venv/bin/activate

if [ "$COLLECTSTATIC" == "1" ]
then
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Check deps

on:
pull_request:
paths:
- setup.py
- requirements.txt
- requirements-dev.txt

env:
DEBIAN_FRONTEND: noninteractive

jobs:
quality:
name: Checking dependency graph
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ['ubuntu-20.04']
python-version: ['3.8']

steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v5
with:
cache: 'pip'
python-version: '3.8.18'

- name: Install dependencies
run: |
pip3 install -c requirements-dev.txt pip-tools

- name: Check dependency graph
run: |
pip-compile -q --strip-extras
pip-compile -q --strip-extras requirements-dev.in

- name: Verify dependency graph is ok
uses: tj-actions/verify-changed-files@v20
id: verify-changed-files
with:
files: |
requirements.txt
requirements-dev.txt

- name: Validating graph
if: steps.verify-changed-files.outputs.files_changed == 'true'
run: |
echo "Dependency file(s) changed: ${{ steps.verify-changed-files.outputs.changed_files }}"
git diff
core.setFailed('Please add your new dependencies in setup.py and/or dev-requirements.in then run pip-compile to add them in requirements. (see docs/contribute/development)')
15 changes: 12 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install dependencies
run: |
sudo apt-get update -q
Expand All @@ -85,11 +87,13 @@ jobs:
pip install -r requirements.txt -U
pip install -r requirements-dev.txt
npm ci

- name: Test with coverage
run: |
cd src
coverage run ./manage.py test
coverage run -a ./manage.py test --settings screamshotter.settings.test_timeout screenshotter.tests.CaptureTestCase.test_timeout_screenshot

- name: Coverage upload
run: |
pip install codecov
Expand All @@ -101,14 +105,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
run: |
docker build -t screamshotter_ci:latest .

- name: Upload image
uses: ishworkh/docker-image-artifact-upload@v1
uses: ishworkh/docker-image-artifact-upload@v2.1.0
with:
image: "screamshotter_ci:latest"

Expand All @@ -123,6 +130,7 @@ jobs:
version: '20.04'
- os: jammy
version: '22.04'

env:
DISTRO: 'ubuntu:${{ matrix.os }}'
CODE: ${{ matrix.version }}
Expand Down Expand Up @@ -150,9 +158,10 @@ jobs:
name: Tests E2E docker
runs-on: ubuntu-latest
needs: [build_docker_image]

steps:
- name: Download image
uses: ishworkh/docker-image-artifact-download@v1
uses: ishworkh/docker-image-artifact-download@v2.1.0
with:
image: "screamshotter_ci:latest"

Expand Down Expand Up @@ -248,7 +257,7 @@ jobs:
name: 'debian-20.04'

- name: Download docker image
uses: ishworkh/docker-image-artifact-download@v1
uses: ishworkh/docker-image-artifact-download@v2.1.0
with:
image: "screamshotter_ci:latest"

Expand Down
18 changes: 9 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ ENV MAX_REQUESTS=250
ENV PUPPETEER_CACHE_DIR=/app/puppeteer/

RUN useradd -ms /bin/bash django
RUN mkdir -p /app/static
RUN chown django:django /app
RUN mkdir -p /app/static /opt
RUN chown django:django /app /opt

RUN apt-get -qq update && apt-get install -qq -y \
gconf-service \
Expand Down Expand Up @@ -81,28 +81,28 @@ RUN apt-get -qq update && apt-get install -qq -y \
RUN wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py && rm get-pip.py

USER django
RUN python3 -m venv /app/venv
RUN /app/venv/bin/pip3 install --no-cache-dir pip setuptools wheel -U
RUN python3 -m venv /opt/venv
RUN /opt/venv/bin/pip3 install --no-cache-dir pip setuptools wheel -U

COPY requirements.txt /app/
RUN /app/venv/bin/pip3 install --no-cache-dir -r /app/requirements.txt -U && rm /app/requirements.txt
RUN /app/venv/bin/nodeenv /app/venv/ -C '' -p -n 20.9.0
RUN /opt/venv/bin/pip3 install --no-cache-dir -r /app/requirements.txt -U && rm /app/requirements.txt
RUN /opt/venv/bin/nodeenv /app/venv/ -C '' -p -n 20.9.0

# upgrade npm & requirements
COPY package.json /app/package.json
COPY package-lock.json /app/package-lock.json
RUN . /app/venv/bin/activate && npm ci && rm /app/*.json
RUN . /opt/venv/bin/activate && npm ci && rm /app/*.json

FROM build AS dev

COPY requirements-dev.txt /app/
RUN /app/venv/bin/pip3 install --no-cache-dir -r /app/requirements-dev.txt -U && rm /app/requirements-dev.txt
RUN /opt/venv/bin/pip3 install --no-cache-dir -r /app/requirements-dev.txt -U && rm /app/requirements-dev.txt

CMD ["./manage.py", "runserver", "0.0.0.0:8000"]

FROM base

COPY --from=build /app/venv /app/venv
COPY --from=build /opt/venv /opt/venv
COPY --from=build /app/node_modules /app/node_modules
COPY --from=build /app/puppeteer /app/puppeteer
COPY src /app/src
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ build_deb:
docker run --name screamshotter_deb_run -t screamshotter_deb bash -c "exit"
docker cp screamshotter_deb_run:/dpkg ./
docker stop screamshotter_deb_run
docker rm screamshotter_deb_run
docker rm screamshotter_deb_run

deps:
docker compose run --rm web bash -c "cd /app && pip-compile -q --strip-extras && pip-compile -q --strip-extras requirements-dev.in"
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
BASE_IMAGE: focal

volumes:
- ./src/:/app/src/
- ./:/app/
ports:
- "8000:8000"
environment:
Expand Down
4 changes: 2 additions & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
#
# pip-compile requirements-dev.in
# pip-compile --strip-extras requirements-dev.in
#
asgiref==3.8.1
# via
Expand All @@ -18,7 +18,7 @@ click==8.1.7
# via pip-tools
coverage==7.6.1
# via -r requirements-dev.in
django==4.2.13
django==4.2.16
# via
# -c ./requirements.txt
# django-debug-toolbar
Expand Down
7 changes: 3 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
#
# pip-compile
# pip-compile --strip-extras
#
asgiref==3.8.1
# via django
backports-zoneinfo==0.2.1 ; python_version < "3.9"
# via
# django
# djangorestframework
# screamshotter (setup.py)
certifi==2024.8.30
# via
Expand All @@ -30,7 +31,7 @@ gevent==24.2.1
# via gunicorn
greenlet==3.1.1
# via gevent
gunicorn[gevent]==23.0.0
gunicorn==23.0.0
# via screamshotter (setup.py)
idna==3.7
# via requests
Expand All @@ -44,8 +45,6 @@ nodeenv==1.9.1
# via screamshotter (setup.py)
packaging==24.1
# via gunicorn
pytz==2024.2
# via djangorestframework
requests==2.32.3
# via coreapi
sentry-sdk==2.15.0
Expand Down
32 changes: 12 additions & 20 deletions src/screenshotter/tests.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import os
from tempfile import TemporaryDirectory
from unittest import skipIf

Expand All @@ -10,7 +9,7 @@
from django.test import SimpleTestCase, override_settings
from django.urls import reverse
from rest_framework.serializers import Serializer
from rest_framework.test import APIClient
from rest_framework.test import APISimpleTestCase

from .exceptions import ScreenshotterException
from .puppeteer import take_screenshot
Expand All @@ -24,26 +23,22 @@ class CaptureTestCase(SimpleTestCase):
@override_settings(MEDIA_ROOT=temp_dir.name)
def test_capture_mime(self):
png = take_screenshot('https://www.google.fr')
png_path = os.path.join(temp_dir.name, 'test.png')

cfile = ContentFile(content=png)
default_storage.save(name=png_path, content=cfile)
default_storage.save(name='test_capture_mime.png', content=cfile)

self.assertTrue(os.path.exists(png_path))
self.assertNotEqual(os.path.getsize(png_path), 0)

mime = magic.from_file(png_path, mime=True)
self.assertNotEqual(cfile.size, 0)
mime = magic.from_buffer(default_storage.open('test_capture_mime.png').read(), mime=True)
self.assertEqual(mime, "image/png", )

@override_settings(MEDIA_ROOT=temp_dir.name)
def test_capture_size(self):
png = take_screenshot('https://www.google.fr', width=1280, height=720)

png_path = os.path.join(temp_dir.name, 'test2.png')
cfile = ContentFile(content=png)
default_storage.save(name=png_path, content=cfile)
default_storage.save(name='test_capture_size.png', content=cfile)

image = Image.open(png_path)
image = Image.open(default_storage.path('test_capture_size.png'))

self.assertEqual(image.width, 1280)
self.assertEqual(image.height, 720)
Expand Down Expand Up @@ -78,23 +73,20 @@ def test_bad_settings(self):
bool(app_settings.BAD_SETTINGS)


class CaptureApiTestCase(SimpleTestCase):
def setUp(self):
self.api_client = APIClient()

class CaptureApiTestCase(APISimpleTestCase):
def test_api_good_request_json(self):
serializer = ScreenshotSerializer()
data = serializer.data
data['url'] = "https://www.google.fr"

response = self.api_client.post(reverse('screenshotter:screenshot') + '?format=json', data=data)
response = self.client.post(reverse('screenshotter:screenshot') + '?format=json', data=data)
data = response.json()
self.assertEqual(response.status_code, 200, data)
self.assertIn('base64', data)

def test_api_bad_request(self):
serializer = ScreenshotSerializer()
response = self.api_client.post(reverse('screenshotter:screenshot') + '?format=json', data=serializer.data)
response = self.client.post(reverse('screenshotter:screenshot') + '?format=json', data=serializer.data)
data = response.json()
self.assertEqual(response.status_code, 400)
self.assertIn('url', data)
Expand All @@ -104,15 +96,15 @@ def test_api_wrong_response(self):
serializer = ScreenshotSerializer()
data = serializer.data
data['url'] = "https://kikou.com"
response = self.api_client.post(reverse('screenshotter:screenshot') + '?format=json', data=data)
response = self.client.post(reverse('screenshotter:screenshot') + '?format=json', data=data)
self.assertEqual(response.status_code, 500, response.json())

def test_api_browsable(self):
serializer = ScreenshotSerializer()
data = serializer.data
data['url'] = "https://www.google.fr"

response = self.api_client.post(reverse('screenshotter:screenshot') + '?format=api', data=data)
response = self.client.post(reverse('screenshotter:screenshot') + '?format=api', data=data)
self.assertEqual(response.status_code, 200)
self.assertIn(b'<html>', response.content)
# check default renderer is json in browsable api (response in "base64": "xxx" format)
Expand All @@ -123,7 +115,7 @@ def test_png_default(self):
data = serializer.data
data['url'] = "https://www.google.fr"

response = self.api_client.post(reverse('screenshotter:screenshot'), data=data)
response = self.client.post(reverse('screenshotter:screenshot'), data=data)
self.assertEqual(response.status_code, 200)
mime = magic.from_buffer(response.content, mime=True)
self.assertEqual(mime, "image/png")
Loading