Merge pull request #2993 from SchrodingersGat/webp-support

webp image support
This commit is contained in:
Oliver 2022-05-18 14:43:28 +10:00 committed by GitHub
commit fd2ec03fab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 54 deletions

View File

@ -3,9 +3,8 @@
# This CI action runs on pushes to either the master or stable branches # This CI action runs on pushes to either the master or stable branches
# 1. Build the development docker image (as per the documentation) # 1. Build the development docker image (as per the documentation)
# 2. Install requied python libs into the docker container # 2. Launch the development server, and update the installation
# 3. Launch the container # 3. Run unit tests within the docker context
# 4. Check that the API endpoint is available
name: Docker Test name: Docker Test
@ -26,12 +25,14 @@ jobs:
- name: Build Docker Image - name: Build Docker Image
run: | run: |
cd docker cd docker
docker-compose -f docker-compose.sqlite.yml build docker-compose build
docker-compose -f docker-compose.sqlite.yml run inventree-dev-server invoke update docker-compose run inventree-dev-server invoke update
docker-compose -f docker-compose.sqlite.yml up -d docker-compose up -d
- name: Sleepy Time - name: Wait for Server
run: sleep 60
- name: Test API
run: | run: |
pip install requests cd docker
python3 ci/check_api_endpoint.py docker-compose run inventree-dev-server invoke wait
- name: Run unit tests
run: |
cd docker
docker-compose run inventree-dev-server invoke test

View File

@ -1,5 +1,7 @@
import json import json
from test.support import EnvironmentVarGuard import os
from unittest import mock
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
import django.core.exceptions as django_exceptions import django.core.exceptions as django_exceptions
@ -449,17 +451,20 @@ class TestSettings(TestCase):
def setUp(self) -> None: def setUp(self) -> None:
self.user_mdl = get_user_model() self.user_mdl = get_user_model()
self.env = EnvironmentVarGuard()
# Create a user for auth # Create a user for auth
user = get_user_model() user = get_user_model()
self.user = user.objects.create_superuser('testuser1', 'test1@testing.com', 'password1') self.user = user.objects.create_superuser('testuser1', 'test1@testing.com', 'password1')
self.client.login(username='testuser1', password='password1') self.client.login(username='testuser1', password='password1')
def run_reload(self): def in_env_context(self, envs={}):
"""Patch the env to include the given dict"""
return mock.patch.dict(os.environ, envs)
def run_reload(self, envs={}):
from plugin import registry from plugin import registry
with self.env: with self.in_env_context(envs):
settings.USER_ADDED = False settings.USER_ADDED = False
registry.reload_plugins() registry.reload_plugins()
@ -475,25 +480,28 @@ class TestSettings(TestCase):
self.assertEqual(user_count(), 1) self.assertEqual(user_count(), 1)
# not enough set # not enough set
self.env.set('INVENTREE_ADMIN_USER', 'admin') # set username self.run_reload({
self.run_reload() 'INVENTREE_ADMIN_USER': 'admin'
})
self.assertEqual(user_count(), 1) self.assertEqual(user_count(), 1)
# enough set # enough set
self.env.set('INVENTREE_ADMIN_USER', 'admin') # set username self.run_reload({
self.env.set('INVENTREE_ADMIN_EMAIL', 'info@example.com') # set email 'INVENTREE_ADMIN_USER': 'admin', # set username
self.env.set('INVENTREE_ADMIN_PASSWORD', 'password123') # set password 'INVENTREE_ADMIN_EMAIL': 'info@example.com', # set email
self.run_reload() 'INVENTREE_ADMIN_PASSWORD': 'password123' # set password
})
self.assertEqual(user_count(), 2) self.assertEqual(user_count(), 2)
# create user manually # create user manually
self.user_mdl.objects.create_user('testuser', 'test@testing.com', 'password') self.user_mdl.objects.create_user('testuser', 'test@testing.com', 'password')
self.assertEqual(user_count(), 3) self.assertEqual(user_count(), 3)
# check it will not be created again # check it will not be created again
self.env.set('INVENTREE_ADMIN_USER', 'testuser') self.run_reload({
self.env.set('INVENTREE_ADMIN_EMAIL', 'test@testing.com') 'INVENTREE_ADMIN_USER': 'testuser',
self.env.set('INVENTREE_ADMIN_PASSWORD', 'password') 'INVENTREE_ADMIN_EMAIL': 'test@testing.com',
self.run_reload() 'INVENTREE_ADMIN_PASSWORD': 'password',
})
self.assertEqual(user_count(), 3) self.assertEqual(user_count(), 3)
# make sure to clean up # make sure to clean up
@ -517,20 +525,30 @@ class TestSettings(TestCase):
def test_helpers_cfg_file(self): def test_helpers_cfg_file(self):
# normal run - not configured # normal run - not configured
self.assertIn('InvenTree/InvenTree/config.yaml', config.get_config_file())
valid = [
'inventree/config.yaml',
'inventree/dev/config.yaml',
]
self.assertTrue(any([opt in config.get_config_file().lower() for opt in valid]))
# with env set # with env set
with self.env: with self.in_env_context({'INVENTREE_CONFIG_FILE': 'my_special_conf.yaml'}):
self.env.set('INVENTREE_CONFIG_FILE', 'my_special_conf.yaml') self.assertIn('inventree/inventree/my_special_conf.yaml', config.get_config_file().lower())
self.assertIn('InvenTree/InvenTree/my_special_conf.yaml', config.get_config_file())
def test_helpers_plugin_file(self): def test_helpers_plugin_file(self):
# normal run - not configured # normal run - not configured
self.assertIn('InvenTree/InvenTree/plugins.txt', config.get_plugin_file())
valid = [
'inventree/plugins.txt',
'inventree/dev/plugins.txt',
]
self.assertTrue(any([opt in config.get_plugin_file().lower() for opt in valid]))
# with env set # with env set
with self.env: with self.in_env_context({'INVENTREE_PLUGIN_FILE': 'my_special_plugins.txt'}):
self.env.set('INVENTREE_PLUGIN_FILE', 'my_special_plugins.txt')
self.assertIn('my_special_plugins.txt', config.get_plugin_file()) self.assertIn('my_special_plugins.txt', config.get_plugin_file())
def test_helpers_setting(self): def test_helpers_setting(self):
@ -539,8 +557,7 @@ class TestSettings(TestCase):
self.assertEqual(config.get_setting(TEST_ENV_NAME, None, '123!'), '123!') self.assertEqual(config.get_setting(TEST_ENV_NAME, None, '123!'), '123!')
# with env set # with env set
with self.env: with self.in_env_context({TEST_ENV_NAME: '321'}):
self.env.set(TEST_ENV_NAME, '321')
self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321') self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321')

View File

@ -1046,24 +1046,29 @@ class PartDetailTests(InvenTreeAPITestCase):
) )
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertIn('Upload a valid image', str(response.data))
# Now try to upload a valid image file # Now try to upload a valid image file, in multiple formats
img = PIL.Image.new('RGB', (128, 128), color='red') for fmt in ['jpg', 'png', 'bmp', 'webp']:
img.save('dummy_image.jpg') fn = f'dummy_image.{fmt}'
with open('dummy_image.jpg', 'rb') as dummy_image: img = PIL.Image.new('RGB', (128, 128), color='red')
response = upload_client.patch( img.save(fn)
url,
{
'image': dummy_image,
},
format='multipart',
)
self.assertEqual(response.status_code, 200) with open(fn, 'rb') as dummy_image:
response = upload_client.patch(
url,
{
'image': dummy_image,
},
format='multipart',
)
# And now check that the image has been set self.assertEqual(response.status_code, 200)
p = Part.objects.get(pk=pk)
# And now check that the image has been set
p = Part.objects.get(pk=pk)
self.assertIsNotNone(p.image)
def test_details(self): def test_details(self):
""" """

View File

@ -2,6 +2,7 @@
from allauth.account.models import EmailAddress from allauth.account.models import EmailAddress
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.test import TestCase from django.test import TestCase
@ -64,11 +65,21 @@ class TemplateTagTest(TestCase):
def test_hash(self): def test_hash(self):
result_hash = inventree_extras.inventree_commit_hash() result_hash = inventree_extras.inventree_commit_hash()
self.assertGreater(len(result_hash), 5) if settings.DOCKER:
# Testing inside docker environment *may* return an empty git commit hash
# In such a case, skip this check
pass
else:
self.assertGreater(len(result_hash), 5)
def test_date(self): def test_date(self):
d = inventree_extras.inventree_commit_date() d = inventree_extras.inventree_commit_date()
self.assertEqual(len(d.split('-')), 3) if settings.DOCKER:
# Testing inside docker environment *may* return an empty git commit hash
# In such a case, skip this check
pass
else:
self.assertEqual(len(d.split('-')), 3)
def test_github(self): def test_github(self):
self.assertIn('github.com', inventree_extras.inventree_github_url()) self.assertIn('github.com', inventree_extras.inventree_github_url())

View File

@ -1,4 +1,4 @@
FROM alpine:3.13 as base FROM alpine:3.14 as base
# GitHub source # GitHub source
ARG repository="https://github.com/inventree/InvenTree.git" ARG repository="https://github.com/inventree/InvenTree.git"
@ -62,13 +62,13 @@ RUN apk -U upgrade
RUN apk add --no-cache git make bash \ RUN apk add --no-cache git make bash \
gcc libgcc g++ libstdc++ \ gcc libgcc g++ libstdc++ \
gnupg \ gnupg \
libjpeg-turbo libjpeg-turbo-dev jpeg jpeg-dev \ libjpeg-turbo libjpeg-turbo-dev jpeg jpeg-dev libwebp-dev \
libffi libffi-dev \ libffi libffi-dev \
zlib zlib-dev \ zlib zlib-dev \
# Special deps for WeasyPrint (these will be deprecated once WeasyPrint drops cairo requirement) # Special deps for WeasyPrint (these will be deprecated once WeasyPrint drops cairo requirement)
cairo cairo-dev pango pango-dev gdk-pixbuf \ cairo cairo-dev pango pango-dev gdk-pixbuf \
# Fonts # Fonts
fontconfig ttf-droid ttf-liberation ttf-dejavu ttf-opensans ttf-ubuntu-font-family font-croscore font-noto \ fontconfig ttf-droid ttf-liberation ttf-dejavu ttf-opensans font-croscore font-noto \
# Core python # Core python
python3 python3-dev py3-pip \ python3 python3-dev py3-pip \
# SQLite support # SQLite support

View File

@ -39,7 +39,7 @@ inventree # Install the latest version of the Inve
isort==5.10.1 # DEV: python import sorting isort==5.10.1 # DEV: python import sorting
markdown==3.3.4 # Force particular version of markdown markdown==3.3.4 # Force particular version of markdown
pep8-naming==0.11.1 # PEP naming convention extension pep8-naming==0.11.1 # PEP naming convention extension
pillow==9.0.1 # Image manipulation pillow==9.1.0 # Image manipulation
py-moneyed==0.8.0 # Specific version requirement for py-moneyed py-moneyed==0.8.0 # Specific version requirement for py-moneyed
pygments==2.7.4 # Syntax highlighting pygments==2.7.4 # Syntax highlighting
python-barcode[images]==0.13.1 # Barcode generator python-barcode[images]==0.13.1 # Barcode generator