87 lines
3 KiB
Python
87 lines
3 KiB
Python
import json
|
|
from types import SimpleNamespace
|
|
import pytest
|
|
|
|
from ocado_grocy.images import add_picture, file_path, image_type
|
|
|
|
|
|
DATA = b'\xff\xd8\xfftest-image'
|
|
|
|
|
|
def product():
|
|
return {'id':72, 'name':'Ocado title', 'description':'<p>Ocado product ID: 123</p>' + json.dumps({'Ocado product ID':'123','image_url':'https://www.ocado.com/images-v3/test.jpg'}), 'picture_file_name':None}
|
|
|
|
|
|
def response(data=DATA):
|
|
return SimpleNamespace(status_code=200, content=data, raise_for_status=lambda:None)
|
|
|
|
|
|
class API:
|
|
url = 'https://grocy.test/api'
|
|
timeout = 30
|
|
def __init__(self):
|
|
self.product = product()
|
|
self.writes = []
|
|
self.stored = DATA
|
|
self.session = self
|
|
def get(self, path, **kwargs):
|
|
if path.startswith(self.url):
|
|
assert '/files/productpictures/' in path
|
|
return response(self.stored)
|
|
assert path == '/objects/products/72'
|
|
return self.product.copy()
|
|
def put(self, path, **kwargs):
|
|
assert path.startswith(self.url + '/files/productpictures/')
|
|
assert kwargs['data'] == DATA
|
|
assert kwargs['headers'] == {'Content-Type':'application/octet-stream'}
|
|
self.writes.append(path)
|
|
return response()
|
|
def request(self, method, path, payload):
|
|
assert method == 'PUT' and path == '/objects/products/72'
|
|
assert set(payload) == {'picture_file_name'}
|
|
self.writes.append(payload)
|
|
self.product.update(payload)
|
|
|
|
|
|
class Downloader:
|
|
def get(self, url, **kwargs):
|
|
assert url == 'https://www.ocado.com/images-v3/test.jpg'
|
|
assert set(kwargs) == {'timeout','allow_redirects'}
|
|
return response()
|
|
|
|
|
|
def test_upload_verifies_file_and_only_sets_picture_field():
|
|
api = API()
|
|
assert add_picture(api, Downloader(), product()) == 'updated'
|
|
assert len(api.writes) == 2
|
|
assert api.product['name'] == 'Ocado title'
|
|
assert api.product['description'] == product()['description']
|
|
assert add_picture(api, Downloader(), api.product) == 'existing_picture'
|
|
assert len(api.writes) == 2
|
|
|
|
|
|
def test_failed_file_verification_does_not_assign_picture():
|
|
api = API()
|
|
api.stored = b'wrong file'
|
|
with pytest.raises(ValueError, match='verification'):
|
|
add_picture(api, Downloader(), product())
|
|
assert api.product['picture_file_name'] is None
|
|
|
|
|
|
def test_concurrent_picture_or_deleted_product_is_preserved():
|
|
api = API()
|
|
api.product['picture_file_name'] = 'user-picture.jpg'
|
|
assert add_picture(api, Downloader(), product()) == 'existing_picture'
|
|
api.product = {}
|
|
assert add_picture(api, Downloader(), product()) == 'deleted_product'
|
|
assert not api.writes
|
|
|
|
|
|
def test_rejects_non_images_and_external_urls():
|
|
with pytest.raises(ValueError):
|
|
image_type(b'<html>not an image</html>')
|
|
p = product()
|
|
p['description'] = p['description'].replace('www.ocado.com', 'example.com')
|
|
with pytest.raises(ValueError, match='Ocado image URL'):
|
|
add_picture(API(), Downloader(), p)
|
|
assert file_path('test.jpg') == '/files/productpictures/dGVzdC5qcGc%3D'
|