18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#!/usr/bin env python
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.cloudsearch2.domain import Domain
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.cloudsearch2.layer1 import CloudSearchConnection
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom tests.compat import mock, unittest
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom httpretty import HTTPretty
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport json
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.cloudsearch2.search import SearchConnection, SearchServiceException
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.compat import six, map
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom tests.unit import AWSMockServiceTestCase
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom tests.unit.cloudsearch2 import DEMO_DOMAIN_DATA
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom tests.unit.cloudsearch2.test_connection import TestCloudSearchCreateDomain
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiHOSTNAME = "search-demo-userdomain.us-east-1.cloudsearch.amazonaws.com"
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiFULL_URL = 'http://%s/2013-01-01/search' % HOSTNAME
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass CloudSearchSearchBaseTest(unittest.TestCase):
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    hits = [
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12341',
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 1',
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 1
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12342',
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 2',
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 2
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12343',
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 3',
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 3
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12344',
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 4',
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 4
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12345',
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 5',
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 5
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12346',
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 6',
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 6
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        {
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'id': '12347',
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'fields': {
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'title': 'Document 7',
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'rank': 7
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            }
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    ]
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    content_type = "text/xml"
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response_status = 200
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_args(self, requestline):
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        (_, request, _) = requestline.split(b" ")
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        (_, request) = request.split(b"?", 1)
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = six.moves.urllib.parse.parse_qs(request)
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return args
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def setUp(self):
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        HTTPretty.enable()
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        body = self.response
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not isinstance(body, bytes):
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            body = json.dumps(body).encode('utf-8')
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        HTTPretty.register_uri(HTTPretty.GET, FULL_URL,
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               body=body,
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               content_type=self.content_type,
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               status=self.response_status)
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def tearDown(self):
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        HTTPretty.disable()
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass CloudSearchSearchTest(CloudSearchSearchBaseTest):
1008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response = {
1018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'rank': '-text_relevance',
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'match-expr': "Test",
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'hits': {
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'found': 30,
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'start': 0,
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'hit': CloudSearchSearchBaseTest.hits
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'status': {
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'rid': 'b7c167f6c2da6d93531b9a7b314ad030b3a74803b4b7797edb905ba5a6a08',
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'time-ms': 2,
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'cpu-time-ms': 0
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_qsearch(self):
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(q='Test', options='TestOptions')
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'q'], [b"Test"])
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'q.options'], [b"TestOptions"])
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'start'], [b"0"])
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'size'], [b"10"])
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_search_details(self):
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(q='Test', size=50, start=20)
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'q'], [b"Test"])
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'size'], [b"50"])
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'start'], [b"20"])
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_facet_constraint_single(self):
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            q='Test',
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            facet={'author': "'John Smith','Mark Smith'"})
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'facet.author'],
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         [b"'John Smith','Mark Smith'"])
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_facet_constraint_multiple(self):
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            q='Test',
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            facet={'author': "'John Smith','Mark Smith'",
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                   'category': "'News','Reviews'"})
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'facet.author'],
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         [b"'John Smith','Mark Smith'"])
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'facet.category'],
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         [b"'News','Reviews'"])
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_facet_sort_single(self):
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(q='Test', facet={'author': {'sort': 'alpha'}})
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        print(args)
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'facet.author'], [b'{"sort": "alpha"}'])
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_facet_sort_multiple(self):
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(q='Test', facet={'author': {'sort': 'alpha'},
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                       'cat': {'sort': 'count'}})
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'facet.author'], [b'{"sort": "alpha"}'])
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'facet.cat'], [b'{"sort": "count"}'])
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_result_fields_single(self):
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(q='Test', return_fields=['author'])
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'return'], [b'author'])
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_result_fields_multiple(self):
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search.search(q='Test', return_fields=['author', 'title'])
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        args = self.get_args(HTTPretty.last_request.raw_requestline)
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(args[b'return'], [b'author,title'])
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_results_meta(self):
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Check returned metadata is parsed correctly"""
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search.search(q='Test')
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # These rely on the default response which is fed into HTTPretty
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.hits, 30)
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.docs[0]['fields']['rank'], 1)
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_results_info(self):
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Check num_pages_needed is calculated correctly"""
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search.search(q='Test')
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # This relies on the default response which is fed into HTTPretty
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.num_pages_needed, 3.0)
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_results_matched(self):
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Check that information objects are passed back through the API
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        correctly.
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        query = search.build_query(q='Test')
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search(query)
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.search_service, search)
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.query, query)
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_results_hits(self):
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Check that documents are parsed properly from AWS"""
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search.search(q='Test')
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        hits = list(map(lambda x: x['id'], results.docs))
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # This relies on the default response which is fed into HTTPretty
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            hits, ["12341", "12342", "12343", "12344",
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                   "12345", "12346", "12347"])
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_results_iterator(self):
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Check the results iterator"""
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search.search(q='Test')
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results_correct = iter(["12341", "12342", "12343", "12344",
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                "12345", "12346", "12347"])
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for x in results:
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertEqual(x['id'], next(results_correct))
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_results_internal_consistancy(self):
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Check the documents length matches the iterator details"""
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search.search(q='Test')
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(len(results), len(results.docs))
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_search_nextpage(self):
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Check next page query is correct"""
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        query1 = search.build_query(q='Test')
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        query2 = search.build_query(q='Test')
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search(query2)
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.next_page().query.start,
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         query1.start + query1.size)
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(query1.q, query2.q)
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass CloudSearchSearchFacetTest(CloudSearchSearchBaseTest):
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response = {
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'rank': '-text_relevance',
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'match-expr': "Test",
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'hits': {
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'found': 30,
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'start': 0,
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'hit': CloudSearchSearchBaseTest.hits
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'status': {
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'rid': 'b7c167f6c2da6d93531b9a7b314ad030b3a74803b4b7797edb905ba5a6a08',
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'time-ms': 2,
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'cpu-time-ms': 0
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        },
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        'facets': {
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'tags': {},
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'animals': {'buckets': [{'count': '2', 'value': 'fish'}, {'count': '1', 'value': 'lions'}]},
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_cloudsearch_search_facets(self):
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        #self.response['facets'] = {'tags': {}}
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        results = search.search(q='Test', facet={'tags': {}})
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertTrue('tags' not in results.facets)
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(results.facets['animals'], {u'lions': u'1', u'fish': u'2'})
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass CloudSearchNonJsonTest(CloudSearchSearchBaseTest):
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response = b'<html><body><h1>500 Internal Server Error</h1></body></html>'
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response_status = 500
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    content_type = 'text/xml'
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_response(self):
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with self.assertRaises(SearchServiceException):
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            search.search(q='Test')
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass CloudSearchUnauthorizedTest(CloudSearchSearchBaseTest):
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response = b'<html><body><h1>403 Forbidden</h1>foo bar baz</body></html>'
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    response_status = 403
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    content_type = 'text/html'
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_response(self):
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(endpoint=HOSTNAME)
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with self.assertRaisesRegexp(SearchServiceException, 'foo bar baz'):
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            search.search(q='Test')
3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass FakeResponse(object):
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    status_code = 405
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    content = b''
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass CloudSearchConnectionTest(AWSMockServiceTestCase):
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    cloudsearch = True
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    connection_class = CloudSearchConnection
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def setUp(self):
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        super(CloudSearchConnectionTest, self).setUp()
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.conn = SearchConnection(
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            endpoint='test-domain.cloudsearch.amazonaws.com'
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        )
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_expose_additional_error_info(self):
3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        mpo = mock.patch.object
3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        fake = FakeResponse()
3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        fake.content = b'Nopenopenope'
3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # First, in the case of a non-JSON, non-403 error.
3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mpo(self.conn.session, 'get', return_value=fake) as mock_request:
3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            with self.assertRaises(SearchServiceException) as cm:
3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.conn.search(q='not_gonna_happen')
3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertTrue('non-json response' in str(cm.exception))
3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertTrue('Nopenopenope' in str(cm.exception))
3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Then with JSON & an 'error' key within.
3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        fake.content = json.dumps({
3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'error': "Something went wrong. Oops."
3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        }).encode('utf-8')
3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with mpo(self.conn.session, 'get', return_value=fake) as mock_request:
3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            with self.assertRaises(SearchServiceException) as cm:
3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.conn.search(q='no_luck_here')
3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertTrue('Unknown error' in str(cm.exception))
3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.assertTrue('went wrong. Oops' in str(cm.exception))
3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def test_proxy(self):
3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn = self.service_connection
3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn.proxy = "127.0.0.1"
3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn.proxy_user = "john.doe"
3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn.proxy_pass="p4ssw0rd"
3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn.proxy_port="8180"
3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn.use_proxy = True
3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        domain = Domain(conn, DEMO_DOMAIN_DATA)
3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        search = SearchConnection(domain=domain)
3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.assertEqual(search.session.proxies, {'http': 'http://john.doe:p4ssw0rd@127.0.0.1:8180'})
388