class TestElasticSearchMapping(TestCase):
    def assertDictEqual(self, a, b):
        default = JSONSerializer().default
        self.assertEqual(json.dumps(a, sort_keys=True, default=default), json.dumps(b, sort_keys=True, default=default))

    def setUp(self):
        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTest)

        # Create ES document
        self.obj = models.SearchTest(title="Hello")
        self.obj.save()

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest': {
                'properties': {
                    'pk': {'index': 'not_analyzed', 'type': 'string', 'store': 'yes', 'include_in_all': False},
                    'content_type': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    '_partials': {'index_analyzer': 'edgengram_analyzer', 'include_in_all': False, 'type': 'string'},
                    'live_filter': {'index': 'not_analyzed', 'type': 'boolean', 'include_in_all': False},
                    'published_date_filter': {'index': 'not_analyzed', 'type': 'date', 'include_in_all': False},
                    'title': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                    'title_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    'content': {'type': 'string', 'include_in_all': True},
                    'callable_indexed_field': {'type': 'string', 'include_in_all': True}
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Get document
        document = self.es_mapping.get_document(self.obj)

        # Check
        expected_result = {
            'pk': str(self.obj.pk),
            'content_type': 'searchtests_searchtest',
            '_partials': ['Hello'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
        }

        self.assertDictEqual(document, expected_result)
    def test_add_model(self):
        self.rebuilder.start()

        # Add model
        self.rebuilder.add_model(models.SearchTest)

        # Check the mapping went into Elasticsearch correctly
        mapping = ElasticSearchMapping(models.SearchTest)
        response = self.es.indices.get_mapping(self.backend.es_index, mapping.get_document_type())

        # Make some minor tweaks to the mapping so it matches what is in ES
        # These are generally minor issues with the way Wagtail is generating the mapping that are being cleaned up by Elasticsearch
        # TODO: Would be nice to fix these
        expected_mapping = mapping.get_mapping()
        expected_mapping['searchtests_searchtest']['properties']['pk']['store'] = True
        expected_mapping['searchtests_searchtest']['properties']['live_filter'].pop('index')
        expected_mapping['searchtests_searchtest']['properties']['live_filter'].pop('include_in_all')
        expected_mapping['searchtests_searchtest']['properties']['published_date_filter']['format'] = 'dateOptionalTime'
        expected_mapping['searchtests_searchtest']['properties']['published_date_filter'].pop('index')

        self.assertDictEqual(expected_mapping, response[self.backend.es_index]['mappings'])
    def test_add_model(self):
        self.rebuilder.start()

        # Add model
        self.rebuilder.add_model(models.SearchTest)

        # Check the mapping went into Elasticsearch correctly
        mapping = ElasticSearchMapping(models.SearchTest)
        response = self.es.indices.get_mapping(self.backend.es_index, mapping.get_document_type())

        # Make some minor tweaks to the mapping so it matches what is in ES
        # These are generally minor issues with the way Wagtail is
        # generating the mapping that are being cleaned up by Elasticsearch
        # TODO: Would be nice to fix these
        expected_mapping = mapping.get_mapping()
        expected_mapping['searchtests_searchtest']['properties']['pk']['store'] = True
        expected_mapping['searchtests_searchtest']['properties']['live_filter'].pop('index')
        expected_mapping['searchtests_searchtest']['properties']['live_filter'].pop('include_in_all')
        expected_mapping['searchtests_searchtest']['properties']['published_date_filter']['format'] = \
            'dateOptionalTime'
        expected_mapping['searchtests_searchtest']['properties']['published_date_filter'].pop('index')

        self.assertDictEqual(expected_mapping, response[self.backend.es_index]['mappings'])
class TestElasticSearchMappingInheritance(TestCase):
    def assertDictEqual(self, a, b):
        default = self.JSONSerializer().default
        self.assertEqual(json.dumps(a, sort_keys=True, default=default), json.dumps(b, sort_keys=True, default=default))

    def setUp(self):
        # Import using a try-catch block to prevent crashes if the elasticsearch-py
        # module is not installed
        try:
            from wagtail.wagtailsearch.backends.elasticsearch import ElasticSearchMapping
            from elasticsearch.serializer import JSONSerializer
        except ImportError:
            raise unittest.SkipTest("elasticsearch-py not installed")

        self.JSONSerializer = JSONSerializer

        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTestChild)

        # Create ES document
        self.obj = models.SearchTestChild(title="Hello", subtitle="World")
        self.obj.save()

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest_searchtests_searchtestchild')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest_searchtests_searchtestchild': {
                'properties': {
                    # New
                    'extra_content': {'type': 'string', 'include_in_all': True},
                    'subtitle': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},

                    # Inherited
                    'pk': {'index': 'not_analyzed', 'type': 'string', 'store': 'yes', 'include_in_all': False},
                    'content_type': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    '_partials': {'index_analyzer': 'edgengram_analyzer', 'include_in_all': False, 'type': 'string'},
                    'live_filter': {'index': 'not_analyzed', 'type': 'boolean', 'include_in_all': False},
                    'published_date_filter': {'index': 'not_analyzed', 'type': 'date', 'include_in_all': False},
                    'title': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                    'title_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    'content': {'type': 'string', 'include_in_all': True},
                    'callable_indexed_field': {'type': 'string', 'include_in_all': True}
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        # This must be tests_searchtest instead of 'tests_searchtest_tests_searchtestchild'
        # as it uses the contents base content type name.
        # This prevents the same object being accidentally indexed twice.
        self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Build document
        document = self.es_mapping.get_document(self.obj)

        # Sort partials
        if '_partials' in document:
            document['_partials'].sort()

        # Check
        expected_result = {
            # New
            'extra_content': '',
            'subtitle': 'World',

            # Changed
            'content_type': 'searchtests_searchtest_searchtests_searchtestchild',

            # Inherited
            'pk': str(self.obj.pk),
            '_partials': ['Hello', 'World'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
        }

        self.assertDictEqual(document, expected_result)
class TestElasticSearchMapping(TestCase):
    def assertDictEqual(self, a, b):
        default = self.JSONSerializer().default
        self.assertEqual(json.dumps(a, sort_keys=True, default=default), json.dumps(b, sort_keys=True, default=default))

    def setUp(self):
        # Import using a try-catch block to prevent crashes if the elasticsearch-py
        # module is not installed
        try:
            from wagtail.wagtailsearch.backends.elasticsearch import ElasticSearchMapping
            from elasticsearch.serializer import JSONSerializer
        except ImportError:
            raise unittest.SkipTest("elasticsearch-py not installed")

        self.JSONSerializer = JSONSerializer

        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTest)

        # Create ES document
        self.obj = models.SearchTest(title="Hello")
        self.obj.save()

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest': {
                'properties': {
                    'pk': {'index': 'not_analyzed', 'type': 'string', 'store': 'yes', 'include_in_all': False},
                    'content_type': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    '_partials': {'index_analyzer': 'edgengram_analyzer', 'include_in_all': False, 'type': 'string'},
                    'live_filter': {'index': 'not_analyzed', 'type': 'boolean', 'include_in_all': False},
                    'published_date_filter': {'index': 'not_analyzed', 'type': 'date', 'include_in_all': False},
                    'title': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                    'title_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    'content': {'type': 'string', 'include_in_all': True},
                    'callable_indexed_field': {'type': 'string', 'include_in_all': True}
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Get document
        document = self.es_mapping.get_document(self.obj)

        # Check
        expected_result = {
            'pk': str(self.obj.pk),
            'content_type': 'searchtests_searchtest',
            '_partials': ['Hello'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
        }

        self.assertDictEqual(document, expected_result)
class TestElasticSearchMappingInheritance(TestCase):
    def assertDictEqual(self, a, b):
        default = self.JSONSerializer().default
        self.assertEqual(json.dumps(a, sort_keys=True, default=default),
                         json.dumps(b, sort_keys=True, default=default))

    def setUp(self):
        # Import using a try-catch block to prevent crashes if the elasticsearch-py
        # module is not installed
        try:
            from wagtail.wagtailsearch.backends.elasticsearch import ElasticSearchMapping
            from elasticsearch.serializer import JSONSerializer
        except ImportError:
            raise unittest.SkipTest("elasticsearch-py not installed")

        self.JSONSerializer = JSONSerializer

        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTestChild)

        # Create ES document
        self.obj = models.SearchTestChild(title="Hello", subtitle="World")
        self.obj.save()

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(),
                         'searchtests_searchtest_searchtests_searchtestchild')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest_searchtests_searchtestchild': {
                'properties': {
                    # New
                    'extra_content': {
                        'type': 'string',
                        'include_in_all': True
                    },
                    'subtitle': {
                        'type': 'string',
                        'include_in_all': True,
                        'index_analyzer': 'edgengram_analyzer'
                    },

                    # Inherited
                    'pk': {
                        'index': 'not_analyzed',
                        'type': 'string',
                        'store': 'yes',
                        'include_in_all': False
                    },
                    'content_type': {
                        'index': 'not_analyzed',
                        'type': 'string',
                        'include_in_all': False
                    },
                    '_partials': {
                        'index_analyzer': 'edgengram_analyzer',
                        'include_in_all': False,
                        'type': 'string'
                    },
                    'live_filter': {
                        'index': 'not_analyzed',
                        'type': 'boolean',
                        'include_in_all': False
                    },
                    'published_date_filter': {
                        'index': 'not_analyzed',
                        'type': 'date',
                        'include_in_all': False
                    },
                    'title': {
                        'type': 'string',
                        'include_in_all': True,
                        'index_analyzer': 'edgengram_analyzer'
                    },
                    'title_filter': {
                        'index': 'not_analyzed',
                        'type': 'string',
                        'include_in_all': False
                    },
                    'content': {
                        'type': 'string',
                        'include_in_all': True
                    },
                    'callable_indexed_field': {
                        'type': 'string',
                        'include_in_all': True
                    }
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        # This must be tests_searchtest instead of 'tests_searchtest_tests_searchtestchild'
        # as it uses the contents base content type name.
        # This prevents the same object being accidentally indexed twice.
        self.assertEqual(self.es_mapping.get_document_id(self.obj),
                         'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Build document
        document = self.es_mapping.get_document(self.obj)

        # Sort partials
        if '_partials' in document:
            document['_partials'].sort()

        # Check
        expected_result = {
            # New
            'extra_content': '',
            'subtitle': 'World',

            # Changed
            'content_type':
            'searchtests_searchtest_searchtests_searchtestchild',

            # Inherited
            'pk': str(self.obj.pk),
            '_partials': ['Hello', 'World'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
        }

        self.assertDictEqual(document, expected_result)
class TestElasticSearchMapping(TestCase):
    def assertDictEqual(self, a, b):
        default = self.JSONSerializer().default
        self.assertEqual(json.dumps(a, sort_keys=True, default=default),
                         json.dumps(b, sort_keys=True, default=default))

    def setUp(self):
        # Import using a try-catch block to prevent crashes if the elasticsearch-py
        # module is not installed
        try:
            from wagtail.wagtailsearch.backends.elasticsearch import ElasticSearchMapping
            from elasticsearch.serializer import JSONSerializer
        except ImportError:
            raise unittest.SkipTest("elasticsearch-py not installed")

        self.JSONSerializer = JSONSerializer

        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTest)

        # Create ES document
        self.obj = models.SearchTest(title="Hello")
        self.obj.save()

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(),
                         'searchtests_searchtest')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest': {
                'properties': {
                    'pk': {
                        'index': 'not_analyzed',
                        'type': 'string',
                        'store': 'yes',
                        'include_in_all': False
                    },
                    'content_type': {
                        'index': 'not_analyzed',
                        'type': 'string',
                        'include_in_all': False
                    },
                    '_partials': {
                        'index_analyzer': 'edgengram_analyzer',
                        'include_in_all': False,
                        'type': 'string'
                    },
                    'live_filter': {
                        'index': 'not_analyzed',
                        'type': 'boolean',
                        'include_in_all': False
                    },
                    'published_date_filter': {
                        'index': 'not_analyzed',
                        'type': 'date',
                        'include_in_all': False
                    },
                    'title': {
                        'type': 'string',
                        'include_in_all': True,
                        'index_analyzer': 'edgengram_analyzer'
                    },
                    'title_filter': {
                        'index': 'not_analyzed',
                        'type': 'string',
                        'include_in_all': False
                    },
                    'content': {
                        'type': 'string',
                        'include_in_all': True
                    },
                    'callable_indexed_field': {
                        'type': 'string',
                        'include_in_all': True
                    }
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        self.assertEqual(self.es_mapping.get_document_id(self.obj),
                         'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Get document
        document = self.es_mapping.get_document(self.obj)

        # Check
        expected_result = {
            'pk': str(self.obj.pk),
            'content_type': 'searchtests_searchtest',
            '_partials': ['Hello'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
        }

        self.assertDictEqual(document, expected_result)
class TestElasticSearchMappingInheritance(TestCase):
    def assertDictEqual(self, a, b):
        default = JSONSerializer().default
        self.assertEqual(
            json.dumps(a, sort_keys=True, default=default), json.dumps(b, sort_keys=True, default=default)
        )

    def setUp(self):
        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTestChild)

        # Create ES document
        self.obj = models.SearchTestChild(title="Hello", subtitle="World", page_id=1)
        self.obj.save()
        self.obj.tags.add("a tag")

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest_searchtests_searchtestchild')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest_searchtests_searchtestchild': {
                'properties': {
                    # New
                    'extra_content': {'type': 'string', 'include_in_all': True},
                    'subtitle': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                    'page': {
                        'type': 'nested',
                        'properties': {
                            'title': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                            'search_description': {'type': 'string', 'include_in_all': True},
                            'live_filter': {'index': 'not_analyzed', 'type': 'boolean', 'include_in_all': False},
                        }
                    },

                    # Inherited
                    'pk': {'index': 'not_analyzed', 'type': 'string', 'store': 'yes', 'include_in_all': False},
                    'content_type': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    '_partials': {'index_analyzer': 'edgengram_analyzer', 'include_in_all': False, 'type': 'string'},
                    'live_filter': {'index': 'not_analyzed', 'type': 'boolean', 'include_in_all': False},
                    'published_date_filter': {'index': 'not_analyzed', 'type': 'date', 'include_in_all': False},
                    'title': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                    'title_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    'content': {'type': 'string', 'include_in_all': True},
                    'callable_indexed_field': {'type': 'string', 'include_in_all': True},
                    'tags': {
                        'type': 'nested',
                        'properties': {
                            'name': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                            'slug_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                        }
                    },
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        # This must be tests_searchtest instead of 'tests_searchtest_tests_searchtestchild'
        # as it uses the contents base content type name.
        # This prevents the same object being accidentally indexed twice.
        self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Build document
        document = self.es_mapping.get_document(self.obj)

        # Sort partials
        if '_partials' in document:
            document['_partials'].sort()

        # Check
        expected_result = {
            # New
            'extra_content': '',
            'subtitle': 'World',
            'page': {
                'title': 'Root',
                'search_description': '',
                'live_filter': True,
            },

            # Changed
            'content_type': 'searchtests_searchtest_searchtests_searchtestchild',

            # Inherited
            'pk': str(self.obj.pk),
            '_partials': ['Hello', 'Root', 'World', 'a tag'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
            'tags': [
                {
                    'name': 'a tag',
                    'slug_filter': 'a-tag',
                }
            ],
        }

        self.assertDictEqual(document, expected_result)
class TestElasticSearchMapping(TestCase):
    def assertDictEqual(self, a, b):
        default = JSONSerializer().default
        self.assertEqual(
            json.dumps(a, sort_keys=True, default=default), json.dumps(b, sort_keys=True, default=default)
        )

    def setUp(self):
        # Create ES mapping
        self.es_mapping = ElasticSearchMapping(models.SearchTest)

        # Create ES document
        self.obj = models.SearchTest(title="Hello")
        self.obj.save()
        self.obj.tags.add("a tag")

    def test_get_document_type(self):
        self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest')

    def test_get_mapping(self):
        # Build mapping
        mapping = self.es_mapping.get_mapping()

        # Check
        expected_result = {
            'searchtests_searchtest': {
                'properties': {
                    'pk': {'index': 'not_analyzed', 'type': 'string', 'store': 'yes', 'include_in_all': False},
                    'content_type': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    '_partials': {'index_analyzer': 'edgengram_analyzer', 'include_in_all': False, 'type': 'string'},
                    'live_filter': {'index': 'not_analyzed', 'type': 'boolean', 'include_in_all': False},
                    'published_date_filter': {'index': 'not_analyzed', 'type': 'date', 'include_in_all': False},
                    'title': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                    'title_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                    'content': {'type': 'string', 'include_in_all': True},
                    'callable_indexed_field': {'type': 'string', 'include_in_all': True},
                    'tags': {
                        'type': 'nested',
                        'properties': {
                            'name': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'},
                            'slug_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
                        }
                    },
                }
            }
        }

        self.assertDictEqual(mapping, expected_result)

    def test_get_document_id(self):
        self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))

    def test_get_document(self):
        # Get document
        document = self.es_mapping.get_document(self.obj)

        # Sort partials
        if '_partials' in document:
            document['_partials'].sort()

        # Check
        expected_result = {
            'pk': str(self.obj.pk),
            'content_type': 'searchtests_searchtest',
            '_partials': ['Hello', 'a tag'],
            'live_filter': False,
            'published_date_filter': None,
            'title': 'Hello',
            'title_filter': 'Hello',
            'callable_indexed_field': 'Callable',
            'content': '',
            'tags': [
                {
                    'name': 'a tag',
                    'slug_filter': 'a-tag',
                }
            ],
        }

        self.assertDictEqual(document, expected_result)