First test for conditional requests

Involves lots of mocking. Part of the issue is that there is no way (?) to
know where repo.json is stored when blender isn't running the show.
This commit is contained in:
gandalf3
2017-07-05 02:45:30 -07:00
parent 3847cc877f
commit 1cefb4eab6
2 changed files with 104 additions and 12 deletions

View File

@@ -21,7 +21,37 @@ SCHEMA_VERSION = 1
class BadAddon(Exception):
pass
def fetch(url, pipe):
# TODO add repolist class
def load_repo(url):
"""
Searches local repo.json for repository with a matching 'url' and returns it
"""
pass #TODO
def write_repo(repo):
"""
Writes repo to local repolist json
"""
pass #TODO
def fetch_repo(url: str) -> dict:
""" Requests repo.json from URL and embeds etag/last-modification headers"""
local_copy = load_repo(url)
headers = {}
if 'etag' in local_copy: headers['If-None-Match'] = local_copy['etag']
if 'last-modified' in local_copy: headers['If-Modified-Since'] = local_copy['last-modified']
resp = requests.get(url, headers=headers)
repo = json.loads(resp.json())
repo['etag'] = resp.headers.get('etag')
repo['last-modified'] = resp.headers.get('last-modified')
write_repo(repo)
def refresh(url):
# we have to explicitly close the end of the pipe we are NOT using,
# otherwise no exception will be generated when the other process closes its end.
pipe[0].close()
@@ -30,18 +60,8 @@ def fetch(url, pipe):
local_repo_path.mkdir(exist_ok=True)
try:
# TODO: do conditional request
re = requests.get(url)
fetch_repojson(url)
pipe[1].send(re.status_code)
repo = re.json()
repo['etag'] = re.headers.get('etag')
repo['last-modified'] = re.headers.get('last-modified')
# just stick it here for now..
dump_repo(local_repo_path, repo)
finally:
pipe[1].close()

View File

@@ -0,0 +1,72 @@
import requests
import unittest
from unittest import mock
from blenderpack import fetch_repo, load_repo, write_repo
from datetime import datetime
import json
# based on https://stackoverflow.com/a/28507806/2730823
# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
cidict = requests.structures.CaseInsensitiveDict
req_headers = cidict(kwargs.get('headers'))
t_fmt = '%a, %m %b %Y %X %Z'
class MockResponse:
def __init__(self, headers: cidict, status_code: int):
self.headers = headers
self.status_code = status_code
def json(self):
return json.dumps({'url': 'http://someurl.tld/repo.json'})
if args[0] == 'http://someurl.tld/repo.json':
resp_headers = cidict({
"ETag": '"2a0094b-b74-55326ced274f3"',
"Last-Modified": 'Sun, 13 Mar 2011 13:38:53 GMT',
})
if req_headers == {}:
resp_code = 200
else:
req_headers = cidict(req_headers)
resp_code = 304 if req_headers.get('if-none-match', '') == resp_headers['etag']\
or datetime.strptime(req_headers.get('if-modified-since', ''), t_fmt) < \
datetime.strptime(resp_headers['last-modified'], t_fmt) \
else 200
return MockResponse(resp_headers, resp_code)
return MockResponse(None, 404)
_mocked_repo_storage = {}
def mocked_load_repo(*args, **kwargs):
global _mocked_repo_storage
if args[0] not in _mocked_repo_storage:
_mocked_repo_storage[args[0]] = {'url': args[0]}
return _mocked_repo_storage[args[0]]
def mocked_write_repo(*args, **kwargs):
global _mocked_repo_storage
_mocked_repo_storage[args[0]['url']] = args[0]
class fetch_url_twice(unittest.TestCase):
@mock.patch('requests.get', side_effect=mocked_requests_get)
@mock.patch('blenderpack.load_repo', side_effect=mocked_load_repo)
@mock.patch('blenderpack.write_repo', side_effect=mocked_write_repo)
def test_fetch(self, mock_write, mock_load, mock_get):
fetch_repo('http://someurl.tld/repo.json')
mock_get.assert_called_with('http://someurl.tld/repo.json', headers={})
fetch_repo('http://someurl.tld/repo.json')
mock_get.assert_called_with('http://someurl.tld/repo.json', headers={
'If-None-Match': '"2a0094b-b74-55326ced274f3"',
'If-Modified-Since': 'Sun, 13 Mar 2011 13:38:53 GMT'
})
if __name__ == '__main__':
unittest.main()