Files
reelbox/server/tests/test_banners.py
T

99 lines
5.0 KiB
Python

import json
import os
from pathlib import Path
import tempfile
import unittest
from test_catalog_api import fixture, load_service
class BannerTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(dir=os.environ.get('TMPDIR'))
self.path = fixture(self.temp.name)
self.api = load_service()
self.catalog = self.api.Catalog(self.path)
def tearDown(self):
self.catalog.close()
self.temp.cleanup()
def test_local_config_reloads_safe_bounded_ads_without_admin_endpoint(self):
config = Path(self.temp.name) / 'banners.json'
self.catalog.close()
self.catalog = self.api.Catalog(self.path, banner_config=config)
self.assertEqual(self.catalog.dispatch('/api/banners/'), {'banners': []})
ad = {'title_en': 'Fixture sponsor', 'title_fa': 'حامی آزمایشی',
'subtitle_en': 'Test only', 'target_url': 'https://sponsor.example/offer',
'image_url': 'https://sponsor.example/banner.jpg', 'secret': 'not public'}
config.write_text(json.dumps({'banners': [ad]}))
result = self.catalog.dispatch('/api/banners/')['banners']
self.assertEqual(len(result), 1)
self.assertEqual(result[0]['title_fa'], ad['title_fa'])
self.assertEqual(result[0]['image_url'], ad['image_url'])
self.assertNotIn('secret', result[0])
config.write_text('{invalid')
self.assertEqual(self.catalog.dispatch('/api/banners/'), {'banners': []})
for target in ['http://evil.example/', 'javascript:alert(1)', '//evil.example/',
'https://a:b@evil.example/', 'https://evil.example:444/',
'https://evil.example/ bad', 'https://evil.example/\\\\bad',
'https://evil.example/%0abad', 'https://',
'https://-bad.example/', 'https://bad..example/', 'https://bad.example./',
'https://evil.example/%zz', 'https://evil.example/' + 'x' * 2048]:
config.write_text(json.dumps({'banners': [{**ad, 'target_url': target}, ad]}))
self.assertEqual(len(self.catalog.dispatch('/api/banners/')['banners']), 1, target)
for row in [None, True, 5, {}, {**ad, 'title_en': 'x' * 81},
{**ad, 'subtitle_en': 'x' * 181}, {**ad, 'title_fa': 'bad\u202etext'},
{**ad, 'image_url': 'http://evil.example/banner.jpg'}]:
config.write_text(json.dumps({'banners': [row, ad]}))
self.assertEqual(len(self.catalog.dispatch('/api/banners/')['banners']), 1, row)
config.write_text(json.dumps({'banners': [ad] * 30}))
self.assertEqual(len(self.catalog.dispatch('/api/banners/')['banners']), 5)
config.write_text(json.dumps({'banners': [{}] * 20 + [ad]}))
self.assertEqual(self.catalog.dispatch('/api/banners/'), {'banners': []})
config.write_text(' ' * 65537)
self.assertEqual(self.catalog.dispatch('/api/banners/'), {'banners': []})
for value in [None, [], {'banners': {}}, {'banners': []}]:
config.write_text(json.dumps(value))
self.assertEqual(self.catalog.dispatch('/api/banners/'), {'banners': []})
for route in ['/api/banners/admin/', '/api/banners/config/']:
with self.assertRaises(self.api.ApiError) as error:
self.catalog.dispatch(route)
self.assertEqual(error.exception.status, 404)
def test_http_banner_endpoint_is_json_no_store_and_rejects_writes(self):
from http.client import HTTPConnection
import threading
server = self.api.make_server(self.catalog, port=0)
worker = threading.Thread(target=server.serve_forever, daemon=True)
worker.start()
try:
for method, expected in [('GET', 200), ('HEAD', 200), ('POST', 405), ('PUT', 405)]:
client = HTTPConnection('127.0.0.1', server.server_port, timeout=5)
client.request(method, '/api/banners/')
response = client.getresponse()
self.assertEqual(response.status, expected)
self.assertEqual(response.getheader('Cache-Control'), 'no-store')
self.assertIn('application/json', response.getheader('Content-Type'))
body = response.read()
if method == 'GET':
self.assertEqual(json.loads(body), {'banners': []})
if method == 'HEAD':
self.assertEqual(body, b'')
client.close()
finally:
server.shutdown()
server.server_close()
worker.join(timeout=5)
def test_read_only_banner_route_defaults_to_empty_ad_list(self):
self.assertEqual(self.catalog.dispatch('/api/banners/'), {'banners': []})
self.assertEqual(self.catalog.dispatch('/api/banners'), {'banners': []})
with self.assertRaises(self.api.ApiError) as error:
self.catalog.dispatch('/api/banners/?url=https://evil.example/')
self.assertEqual(error.exception.status, 400)
if __name__ == '__main__':
unittest.main()