on ec4e48e help sign in
searx/tests/unit/test_webapp.py
243 lines 9.4 kB history raw
1# -*- coding: utf-8 -*-
3import json
4from urllib.parse import ParseResult
5from mock import Mock
6from searx.testing import SearxTestCase
7from searx.search import Search
8import searx.engines
11class ViewsTestCase(SearxTestCase):
13 def setUp(self):
14 # skip init function (no external HTTP request)
15 self.setattr4test(searx.engines, 'initialize_engines', searx.engines.load_engines)
17 from searx import webapp # pylint disable=import-outside-toplevel
19 webapp.app.config['TESTING'] = True # to get better error messages
20 self.app = webapp.app.test_client()
22 # set some defaults
23 test_results = [
24 {
25 'content': 'first test content',
26 'title': 'First Test',
27 'url': 'http://first.test.xyz',
28 'engines': ['youtube', 'startpage'],
29 'engine': 'startpage',
30 'parsed_url': ParseResult(scheme='http', netloc='first.test.xyz', path='/', params='', query='', fragment=''), # noqa
31 }, {
32 'content': 'second test content',
33 'title': 'Second Test',
34 'url': 'http://second.test.xyz',
35 'engines': ['youtube', 'startpage'],
36 'engine': 'youtube',
37 'parsed_url': ParseResult(scheme='http', netloc='second.test.xyz', path='/', params='', query='', fragment=''), # noqa
38 },
39 ]
41 timings = [
42 {
43 'engine': 'startpage',
44 'total': 0.8,
45 'load': 0.7
46 },
47 {
48 'engine': 'youtube',
49 'total': 0.9,
50 'load': 0.6
51 }
52 ]
54 def search_mock(search_self, *args):
55 search_self.result_container = Mock(get_ordered_results=lambda: test_results,
56 answers=dict(),
57 corrections=set(),
58 suggestions=set(),
59 infoboxes=[],
60 unresponsive_engines=set(),
61 results=test_results,
62 results_number=lambda: 3,
63 results_length=lambda: len(test_results),
64 get_timings=lambda: timings,
65 redirect_url=None,
66 engine_data={})
68 self.setattr4test(Search, 'search', search_mock)
70 def get_current_theme_name_mock(override=None):
71 if override:
72 return override
73 return 'oscar'
75 self.setattr4test(webapp, 'get_current_theme_name', get_current_theme_name_mock)
77 self.maxDiff = None # to see full diffs
79 def test_index_empty(self):
80 result = self.app.post('/')
81 self.assertEqual(result.status_code, 200)
82 self.assertIn(b'<div class="text-hide center-block" id="main-logo">'
83 + b'<img class="center-block img-responsive" src="/static/themes/oscar/img/logo_searx_a.png"'
84 + b' alt="searx logo" />searx</div>', result.data)
86 def test_index_html_post(self):
87 result = self.app.post('/', data={'q': 'test'})
88 self.assertEqual(result.status_code, 308)
89 self.assertEqual(result.location, 'http://localhost/search')
91 def test_index_html_get(self):
92 result = self.app.post('/?q=test')
93 self.assertEqual(result.status_code, 308)
94 self.assertEqual(result.location, 'http://localhost/search?q=test')
96 def test_search_empty_html(self):
97 result = self.app.post('/search', data={'q': ''})
98 self.assertEqual(result.status_code, 200)
99 self.assertIn(b'<span class="instance pull-left"><a href="/">searx</a></span>', result.data)
101 def test_search_empty_json(self):
102 result = self.app.post('/search', data={'q': '', 'format': 'json'})
103 self.assertEqual(result.status_code, 400)
105 def test_search_empty_csv(self):
106 result = self.app.post('/search', data={'q': '', 'format': 'csv'})
107 self.assertEqual(result.status_code, 400)
109 def test_search_empty_rss(self):
110 result = self.app.post('/search', data={'q': '', 'format': 'rss'})
111 self.assertEqual(result.status_code, 400)
113 def test_search_html(self):
114 result = self.app.post('/search', data={'q': 'test'})
116 self.assertIn(
117 b'<h4 class="result_header" id="result-2"><img width="32" height="32" class="favicon"'
118 + b' src="/static/themes/oscar/img/icons/youtube.png" alt="youtube" /><a href="http://second.test.xyz"'
119 + b' rel="noreferrer" aria-labelledby="result-2">Second <span class="highlight">Test</span></a></h4>', # noqa
120 result.data
121 )
122 self.assertIn(
123 b'<p class="result-content">second <span class="highlight">test</span> content</p>', # noqa
124 result.data
125 )
127 def test_index_json(self):
128 result = self.app.post('/', data={'q': 'test', 'format': 'json'})
129 self.assertEqual(result.status_code, 308)
131 def test_search_json(self):
132 result = self.app.post('/search', data={'q': 'test', 'format': 'json'})
133 result_dict = json.loads(result.data.decode())
135 self.assertEqual('test', result_dict['query'])
136 self.assertEqual(len(result_dict['results']), 2)
137 self.assertEqual(result_dict['results'][0]['content'], 'first test content')
138 self.assertEqual(result_dict['results'][0]['url'], 'http://first.test.xyz')
140 def test_index_csv(self):
141 result = self.app.post('/', data={'q': 'test', 'format': 'csv'})
142 self.assertEqual(result.status_code, 308)
144 def test_search_csv(self):
145 result = self.app.post('/search', data={'q': 'test', 'format': 'csv'})
147 self.assertEqual(
148 b'title,url,content,host,engine,score,type\r\n'
149 b'First Test,http://first.test.xyz,first test content,first.test.xyz,startpage,,result\r\n' # noqa
150 b'Second Test,http://second.test.xyz,second test content,second.test.xyz,youtube,,result\r\n', # noqa
151 result.data
152 )
154 def test_index_rss(self):
155 result = self.app.post('/', data={'q': 'test', 'format': 'rss'})
156 self.assertEqual(result.status_code, 308)
158 def test_search_rss(self):
159 result = self.app.post('/search', data={'q': 'test', 'format': 'rss'})
161 self.assertIn(
162 b'<description>Search results for "test" - searx</description>',
163 result.data
164 )
166 self.assertIn(
167 b'<opensearch:totalResults>3</opensearch:totalResults>',
168 result.data
169 )
171 self.assertIn(
172 b'<title>First Test</title>',
173 result.data
174 )
176 self.assertIn(
177 b'<link>http://first.test.xyz</link>',
178 result.data
179 )
181 self.assertIn(
182 b'<description>first test content</description>',
183 result.data
184 )
186 def test_about(self):
187 result = self.app.get('/about')
188 self.assertEqual(result.status_code, 200)
189 self.assertIn(b'<h1>About <a href="/">searx</a></h1>', result.data)
191 def test_preferences(self):
192 result = self.app.get('/preferences')
193 self.assertEqual(result.status_code, 200)
194 self.assertIn(
195 b'<form method="post" action="/preferences" id="search_form">',
196 result.data
197 )
198 self.assertIn(
199 b'<label class="col-sm-3 col-md-2" for="categories">Default categories</label>',
200 result.data
201 )
202 self.assertIn(
203 b'<label class="col-sm-3 col-md-2" for="locale">Interface language</label>',
204 result.data
205 )
207 def test_browser_locale(self):
208 result = self.app.get('/preferences', headers={'Accept-Language': 'zh-tw;q=0.8'})
209 self.assertEqual(result.status_code, 200)
210 self.assertIn(
211 b'<option value="zh_TW" selected="selected">',
212 result.data,
213 'Interface locale ignored browser preference.'
214 )
215 self.assertIn(
216 b'<option value="zh-TW" selected="selected">',
217 result.data,
218 'Search language ignored browser preference.'
219 )
221 def test_stats(self):
222 result = self.app.get('/stats')
223 self.assertEqual(result.status_code, 404)
225 def test_robots_txt(self):
226 result = self.app.get('/robots.txt')
227 self.assertEqual(result.status_code, 200)
228 self.assertIn(b'Allow: /', result.data)
230 def test_opensearch_xml(self):
231 result = self.app.get('/opensearch.xml')
232 self.assertEqual(result.status_code, 200)
233 self.assertIn(b'<Description>a privacy-respecting, hackable metasearch engine</Description>', result.data)
235 def test_favicon(self):
236 result = self.app.get('/favicon.ico')
237 self.assertEqual(result.status_code, 200)
239 def test_config(self):
240 result = self.app.get('/config')
241 self.assertEqual(result.status_code, 200)
242 json_result = result.get_json()
243 self.assertTrue(json_result)