|
| 1 | +from mock import patch |
| 2 | + |
1 | 3 | from elasticsearch import helpers, TransportError |
| 4 | +from elasticsearch.helpers import ScanError |
2 | 5 |
|
3 | 6 | from . import ElasticsearchTestCase |
4 | 7 | from ..test_cases import SkipTest |
@@ -305,6 +308,24 @@ def test_errors_are_collected_properly(self): |
305 | 308 |
|
306 | 309 |
|
307 | 310 | class TestScan(ElasticsearchTestCase): |
| 311 | + mock_scroll_responses = [ |
| 312 | + { |
| 313 | + '_scroll_id': 'dummy_id', |
| 314 | + '_shards': {'successful': 4, 'total': 5}, |
| 315 | + 'hits': {'hits': [{'scroll_data': 42}]}, |
| 316 | + }, |
| 317 | + { |
| 318 | + '_scroll_id': 'dummy_id', |
| 319 | + '_shards': {'successful': 4, 'total': 5}, |
| 320 | + 'hits': {'hits': []}, |
| 321 | + }, |
| 322 | + ] |
| 323 | + |
| 324 | + @classmethod |
| 325 | + def tearDownClass(cls): |
| 326 | + cls.client.transport.perform_request('DELETE', '/_search/scroll/_all') |
| 327 | + super(TestScan, cls).tearDownClass() |
| 328 | + |
308 | 329 | def test_order_can_be_preserved(self): |
309 | 330 | bulk = [] |
310 | 331 | for x in range(100): |
@@ -338,6 +359,117 @@ def test_all_documents_are_read(self): |
338 | 359 | self.assertEquals(set(map(str, range(100))), set(d["_id"] for d in docs)) |
339 | 360 | self.assertEquals(set(range(100)), set(d["_source"]["answer"] for d in docs)) |
340 | 361 |
|
| 362 | + def test_scroll_error(self): |
| 363 | + bulk = [] |
| 364 | + for x in range(4): |
| 365 | + bulk.append({"index": {"_index": "test_index", "_type": "_doc"}}) |
| 366 | + bulk.append({"value": x}) |
| 367 | + self.client.bulk(bulk, refresh=True) |
| 368 | + |
| 369 | + with patch.object(self.client, 'scroll') as scroll_mock: |
| 370 | + scroll_mock.side_effect = self.mock_scroll_responses |
| 371 | + data = list(helpers.scan( |
| 372 | + self.client, |
| 373 | + index='test_index', |
| 374 | + size=2, |
| 375 | + raise_on_error=False, |
| 376 | + clear_scroll=False |
| 377 | + )) |
| 378 | + self.assertEqual(len(data), 3) |
| 379 | + self.assertEqual(data[-1], {'scroll_data': 42}) |
| 380 | + |
| 381 | + scroll_mock.side_effect = self.mock_scroll_responses |
| 382 | + with self.assertRaises(ScanError): |
| 383 | + data = list(helpers.scan( |
| 384 | + self.client, |
| 385 | + index='test_index', |
| 386 | + size=2, |
| 387 | + raise_on_error=True, |
| 388 | + clear_scroll=False |
| 389 | + )) |
| 390 | + self.assertEqual(len(data), 3) |
| 391 | + self.assertEqual(data[-1], {'scroll_data': 42}) |
| 392 | + |
| 393 | + def test_initial_search_error(self): |
| 394 | + with patch.object(self, 'client') as client_mock: |
| 395 | + client_mock.search.return_value = { |
| 396 | + '_scroll_id': 'dummy_id', |
| 397 | + '_shards': {'successful': 4, 'total': 5}, |
| 398 | + 'hits': {'hits': [{'search_data': 1}]}, |
| 399 | + } |
| 400 | + client_mock.scroll.side_effect = self.mock_scroll_responses |
| 401 | + |
| 402 | + data = list(helpers.scan(self.client, index='test_index', size=2, raise_on_error=False)) |
| 403 | + self.assertEqual(data, [{'search_data': 1}, {'scroll_data': 42}]) |
| 404 | + |
| 405 | + client_mock.scroll.side_effect = self.mock_scroll_responses |
| 406 | + with self.assertRaises(ScanError): |
| 407 | + data = list( |
| 408 | + helpers.scan(self.client, index='test_index', size=2, raise_on_error=True) |
| 409 | + ) |
| 410 | + self.assertEqual(data, [{'search_data': 1}]) |
| 411 | + client_mock.scroll.assert_not_called() |
| 412 | + |
| 413 | + def test_no_scroll_id_fast_route(self): |
| 414 | + with patch.object(self, 'client') as client_mock: |
| 415 | + client_mock.search.return_value = {'no': '_scroll_id'} |
| 416 | + data = list(helpers.scan(self.client, index='test_index')) |
| 417 | + |
| 418 | + self.assertEqual(data, []) |
| 419 | + client_mock.scroll.assert_not_called() |
| 420 | + client_mock.clear_scroll.assert_not_called() |
| 421 | + |
| 422 | + @patch('elasticsearch.helpers.actions.logger') |
| 423 | + def test_logger(self, logger_mock): |
| 424 | + bulk = [] |
| 425 | + for x in range(4): |
| 426 | + bulk.append({'index': {'_index': 'test_index', '_type': '_doc'}}) |
| 427 | + bulk.append({'value': x}) |
| 428 | + self.client.bulk(bulk, refresh=True) |
| 429 | + |
| 430 | + with patch.object(self.client, 'scroll') as scroll_mock: |
| 431 | + scroll_mock.side_effect = self.mock_scroll_responses |
| 432 | + list(helpers.scan( |
| 433 | + self.client, |
| 434 | + index='test_index', |
| 435 | + size=2, |
| 436 | + raise_on_error=False, |
| 437 | + clear_scroll=False |
| 438 | + )) |
| 439 | + logger_mock.warning.assert_called() |
| 440 | + |
| 441 | + scroll_mock.side_effect = self.mock_scroll_responses |
| 442 | + try: |
| 443 | + list(helpers.scan( |
| 444 | + self.client, |
| 445 | + index='test_index', |
| 446 | + size=2, |
| 447 | + raise_on_error=True, |
| 448 | + clear_scroll=False |
| 449 | + )) |
| 450 | + except ScanError: |
| 451 | + pass |
| 452 | + logger_mock.warning.assert_called() |
| 453 | + |
| 454 | + def test_clear_scroll(self): |
| 455 | + bulk = [] |
| 456 | + for x in range(4): |
| 457 | + bulk.append({'index': {'_index': 'test_index', '_type': '_doc'}}) |
| 458 | + bulk.append({'value': x}) |
| 459 | + self.client.bulk(bulk, refresh=True) |
| 460 | + |
| 461 | + with patch.object(self.client, 'clear_scroll', wraps=self.client.clear_scroll) as spy: |
| 462 | + list(helpers.scan(self.client, index='test_index', size=2)) |
| 463 | + spy.assert_called_once() |
| 464 | + |
| 465 | + spy.reset_mock() |
| 466 | + list(helpers.scan(self.client, index='test_index', size=2, clear_scroll=True)) |
| 467 | + spy.assert_called_once() |
| 468 | + |
| 469 | + spy.reset_mock() |
| 470 | + list(helpers.scan(self.client, index='test_index', size=2, clear_scroll=False)) |
| 471 | + spy.assert_not_called() |
| 472 | + |
341 | 473 |
|
342 | 474 | class TestReindex(ElasticsearchTestCase): |
343 | 475 | def setUp(self): |
|
0 commit comments