Skip to content

Commit b9145ad

Browse files
Paolo Romolinixrmx
Paolo Romolini
authored andcommitted
tests: first stab at unit testing search
You got to start from somwhere
1 parent 3291e41 commit b9145ad

File tree

2 files changed

+310
-0
lines changed

2 files changed

+310
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
search_project_response = """
2+
{
3+
"took": 17,
4+
"timed_out": false,
5+
"_shards": {
6+
"total": 5,
7+
"successful": 5,
8+
"skipped": 0,
9+
"failed": 0
10+
},
11+
"hits": {
12+
"total": 1,
13+
"max_score": 1.8232156,
14+
"hits": [
15+
{
16+
"_index": "readthedocs",
17+
"_type": "project",
18+
"_id": "6",
19+
"_score": 1.8232156,
20+
"_source": {
21+
"name": "Pip",
22+
"description": "",
23+
"lang": "en",
24+
"url": "/projects/pip/",
25+
"slug": "pip"
26+
},
27+
"highlight": {
28+
"name": [
29+
"<em>Pip</em>"
30+
]
31+
}
32+
}
33+
]
34+
},
35+
"aggregations": {
36+
"language": {
37+
"doc_count_error_upper_bound": 0,
38+
"sum_other_doc_count": 0,
39+
"buckets": [
40+
{
41+
"key": "en",
42+
"doc_count": 1
43+
}
44+
]
45+
}
46+
}
47+
}
48+
"""
49+
50+
search_file_response = """
51+
{
52+
"took": 27,
53+
"timed_out": false,
54+
"_shards": {
55+
"total": 5,
56+
"successful": 5,
57+
"skipped": 0,
58+
"failed": 0
59+
},
60+
"hits": {
61+
"total": 3,
62+
"max_score": 6.989019,
63+
"hits": [
64+
{
65+
"_index": "readthedocs",
66+
"_type": "page",
67+
"_id": "AWKuy4jp-H7vMtbTbHP5",
68+
"_score": 6.989019,
69+
"_routing": "prova",
70+
"_source": {
71+
"path": "_docs/cap2",
72+
"project": "prova",
73+
"title": "Capitolo 2",
74+
"version": "latest"
75+
},
76+
"highlight": {
77+
"headers": [
78+
"<em>Capitolo</em> 2"
79+
],
80+
"title": [
81+
"<em>Capitolo</em> 2"
82+
],
83+
"content": [
84+
"<em>Capitolo</em> 2 In questo <em>capitolo</em>, vengono trattate"
85+
]
86+
}
87+
},
88+
{
89+
"_index": "readthedocs",
90+
"_type": "page",
91+
"_id": "AWKuy4jp-H7vMtbTbHP4",
92+
"_score": 6.973402,
93+
"_routing": "prova",
94+
"_source": {
95+
"path": "_docs/cap1",
96+
"project": "prova",
97+
"title": "Capitolo 1",
98+
"version": "latest"
99+
},
100+
"highlight": {
101+
"headers": [
102+
"<em>Capitolo</em> 1"
103+
],
104+
"title": [
105+
"<em>Capitolo</em> 1"
106+
],
107+
"content": [
108+
"<em>Capitolo</em> 1 In questo <em>capitolo</em>, le funzioni principali"
109+
]
110+
}
111+
},
112+
{
113+
"_index": "readthedocs",
114+
"_type": "page",
115+
"_id": "AWKuy4jp-H7vMtbTbHP3",
116+
"_score": 0.2017303,
117+
"_routing": "prova",
118+
"_source": {
119+
"path": "index",
120+
"project": "prova",
121+
"title": "Titolo del documento",
122+
"version": "latest"
123+
},
124+
"highlight": {
125+
"content": [
126+
"Titolo del documento Nel <em>Capitolo</em> 1 Nel <em>Capitolo</em> 2"
127+
]
128+
}
129+
}
130+
]
131+
},
132+
"aggregations": {
133+
"project": {
134+
"doc_count_error_upper_bound": 0,
135+
"sum_other_doc_count": 0,
136+
"buckets": [
137+
{
138+
"key": "prova",
139+
"doc_count": 3
140+
}
141+
]
142+
},
143+
"taxonomy": {
144+
"doc_count_error_upper_bound": 0,
145+
"sum_other_doc_count": 0,
146+
"buckets": []
147+
},
148+
"version": {
149+
"doc_count_error_upper_bound": 0,
150+
"sum_other_doc_count": 0,
151+
"buckets": [
152+
{
153+
"key": "latest",
154+
"doc_count": 3
155+
}
156+
]
157+
}
158+
}
159+
}
160+
"""
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import (
3+
absolute_import, division, print_function, unicode_literals)
4+
5+
import json
6+
7+
from django.core.urlresolvers import reverse
8+
from django.test import TestCase, RequestFactory
9+
from mock import patch
10+
from urllib3._collections import HTTPHeaderDict
11+
12+
from readthedocs.projects.models import Project
13+
from readthedocs.rtd_tests.mocks.search_mock_responses import (
14+
search_project_response, search_file_response
15+
)
16+
17+
18+
class TestSearch(TestCase):
19+
fixtures = ['eric', 'test_data']
20+
21+
def setUp(self):
22+
self.client.login(username='eric', password='test')
23+
self.pip = Project.objects.get(slug='pip')
24+
self.factory = RequestFactory()
25+
26+
def perform_request_file_mock(self, method, url, params=None, body=None, timeout=None, ignore=()):
27+
"""
28+
Elastic Search Urllib3HttpConnection mock for file search
29+
"""
30+
headers = HTTPHeaderDict({
31+
'content-length': '893',
32+
'content-type': 'application/json; charset=UTF-8'
33+
})
34+
raw_data = search_file_response
35+
return 200, headers, raw_data
36+
37+
def perform_request_project_mock(self, method, url, params=None, body=None, timeout=None, ignore=()):
38+
"""
39+
Elastic Search Urllib3HttpConnection mock for project search
40+
"""
41+
headers = HTTPHeaderDict({
42+
'content-length': '893',
43+
'content-type': 'application/json; charset=UTF-8'
44+
})
45+
raw_data = search_project_response
46+
return 200, headers, raw_data
47+
48+
@patch(
49+
'elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request',
50+
side_effect=perform_request_project_mock
51+
)
52+
def test_search_project(self, perform_request_mock):
53+
"""
54+
Tests the search view (by project) by mocking the perform request method
55+
of the elastic search module. Checks the query string provided
56+
to elastic search.
57+
"""
58+
self.client.login(username='eric', password='test')
59+
r = self.client.get(
60+
reverse('search'),
61+
{'q': 'pip', 'type': 'project', 'project': None}
62+
)
63+
self.assertEqual(r.status_code, 200)
64+
response = perform_request_mock.call_args_list[0][0][3]
65+
query_dict = json.loads(response)
66+
self.assertIn('query', query_dict)
67+
self.assertDictEqual({
68+
'bool': {
69+
'should': [
70+
{'match': {'name': {'query': 'pip', 'boost': 10}}},
71+
{'match': {'description': {'query': 'pip'}}}
72+
]
73+
}
74+
}, query_dict['query'])
75+
main_hit = r.context['results']['hits']['hits'][0]
76+
self.assertEqual(r.status_code, 200)
77+
self.assertEqual(main_hit['_type'], 'project')
78+
self.assertEqual(main_hit['_type'], 'project')
79+
self.assertEqual(main_hit['fields']['name'], 'Pip')
80+
self.assertEqual(main_hit['fields']['slug'], 'pip')
81+
82+
@patch(
83+
'elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request',
84+
side_effect=perform_request_file_mock
85+
)
86+
def test_search_file(self, perform_request_mock):
87+
"""
88+
Tests the search view (by file) by mocking the perform request method
89+
of the elastic search module. Checks the query string provided
90+
to elastic search.
91+
"""
92+
self.client.login(username='eric', password='test')
93+
r = self.client.get(
94+
reverse('search'),
95+
{'q': 'capitolo', 'type': 'file'}
96+
)
97+
response = perform_request_mock.call_args_list[0][0][3]
98+
query_dict = json.loads(response)
99+
self.assertIn('query', query_dict)
100+
self.assertDictEqual({
101+
'bool': {
102+
'filter': [{'term': {'version': 'latest'}}],
103+
'should': [
104+
{'match_phrase': {'title': {'query': 'capitolo', 'boost': 10, 'slop': 2}}},
105+
{'match_phrase': {'headers': {'query': 'capitolo', 'boost': 5, 'slop': 3}}},
106+
{'match_phrase': {'content': {'query': 'capitolo', 'slop': 5}}}
107+
]
108+
}
109+
}, query_dict['query'])
110+
main_hit = r.context['results']['hits']['hits'][0]
111+
self.assertEqual(r.status_code, 200)
112+
self.assertEqual(main_hit['_type'], 'page')
113+
self.assertEqual(main_hit['fields']['project'], 'prova')
114+
self.assertEqual(main_hit['fields']['path'], '_docs/cap2')
115+
116+
@patch(
117+
'elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request',
118+
side_effect=perform_request_file_mock
119+
)
120+
def test_search_in_project(self, perform_request_mock):
121+
"""
122+
Tests the search view (by file) by mocking the perform request method
123+
of the elastic search module. Checks the query string provided
124+
to elastic search.
125+
"""
126+
self.client.login(username='eric', password='test')
127+
r = self.client.get(
128+
'/projects/pip/search/',
129+
{'q': 'capitolo'}
130+
)
131+
response = perform_request_mock.call_args_list[0][0][3]
132+
query_dict = json.loads(response)
133+
self.assertDictEqual({
134+
'bool': {
135+
'should': [
136+
{'match': {'title': {'boost': 10, 'query': 'capitolo'}}},
137+
{'match': {'headers': {'boost': 5, 'query': 'capitolo'}}},
138+
{'match': {'content': {'query': 'capitolo'}}}
139+
],
140+
'filter': [
141+
{'term': {'project': 'pip'}},
142+
{'term': {'version': 'latest'}}
143+
]
144+
}
145+
}, query_dict['query'])
146+
main_hit = r.context['results']['hits']['hits'][0]
147+
self.assertEqual(r.status_code, 200)
148+
self.assertEqual(main_hit['_type'], 'page')
149+
self.assertEqual(main_hit['fields']['project'], 'prova')
150+
self.assertEqual(main_hit['fields']['path'], '_docs/cap2')

0 commit comments

Comments
 (0)