Skip to content

Commit

Permalink
Improve tests.
Browse files Browse the repository at this point in the history
- Simplify the whole module to make it work with 1.8
- Pass all tests but restframework contrib's for django 1.8
- Fix a false positive on the es query fallback
  • Loading branch information
lauxley committed May 22, 2015
1 parent c18739c commit 53cb5ee
Show file tree
Hide file tree
Showing 14 changed files with 78 additions and 100 deletions.
5 changes: 2 additions & 3 deletions django_elasticsearch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
'ELASTICSEARCH_URL',
'http://localhost:9200'),
**getattr(settings,
'ELASTICSEARCH_CONNECTION_KWARGS',
{})
)
'ELASTICSEARCH_CONNECTION_KWARGS',
{}))
8 changes: 7 additions & 1 deletion django_elasticsearch/contrib/restframework.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
from rest_framework.decorators import list_route
from rest_framework.filters import OrderingFilter
from rest_framework.filters import DjangoFilterBackend
from rest_framework.pagination import PaginationSerializer
try:
from rest_framework.pagination import PaginationSerializer
except ImportError:
# TODO: restframework 3.0
class PaginationSerializer(object):
pass

from rest_framework.serializers import BaseSerializer

from elasticsearch import NotFoundError
Expand Down
6 changes: 1 addition & 5 deletions django_elasticsearch/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def __init__(self, k):
raise TypeError

self.serializer = None
self._fields = []
self._mapping = None

def get_index(self):
Expand Down Expand Up @@ -233,11 +232,8 @@ def do_update(self):
es_client.indices.refresh(index=self.index)

def get_fields(self):
if self._fields:
return self._fields
model_fields = [f.name for f in self.model._meta.fields]
self._fields = self.model.Elasticsearch.fields or model_fields
return self._fields
return self.model.Elasticsearch.fields or model_fields

def make_mapping(self):
"""
Expand Down
40 changes: 1 addition & 39 deletions django_elasticsearch/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,6 @@
from unittest import TestSuite
from unittest import TestLoader
from unittest import TestCase

from django_elasticsearch.tests.models import TestModel
from django_elasticsearch.tests.test_views import EsViewTestCase
from django_elasticsearch.tests.test_qs import EsQuerysetTestCase
from django_elasticsearch.tests.test_indexable import EsIndexableTestCase

__all__ = ['EsQuerysetTestCase', 'EsViewTestCase', 'EsIndexableTestCase', 'EsRestFrameworkTestCase']

try:
from django_elasticsearch.tests.test_restframework import EsRestFrameworkTestCase
except Exception, e:
print 'Skipping test of restframework contrib, reason: ', e

class FakeTestCase(TestCase):
"""
Note: have to do this, because if i append the TestCase to the suit
dynamically i can't call it with test django_elasticsearch.MyTest
"""
pass
EsRestFrameworkTestCase = FakeTestCase
else:
print 'App restframework found, testing contrib.restframework'


def suite():
suite = TestSuite()
loader = TestLoader()

test_cases = [
EsViewTestCase,
EsQuerysetTestCase,
EsIndexableTestCase,
EsRestFrameworkTestCase]

if not TestModel.es.check_cluster():
print "Test skipped. Could not connect to elasticsearch."
else:
for test_case in test_cases:
tests = loader.loadTestsFromTestCase(test_case)
suite.addTests(tests)

return suite
17 changes: 8 additions & 9 deletions django_elasticsearch/tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@


class TestModelESSerializer(ModelJsonSerializer):
def serialize_last_login(self, instance, field_name):
def serialize_date_joined(self, instance, field_name):
d = getattr(instance, field_name)

# a rather typical api output
return {
'iso': d.isoformat(),
'date': d.date().isoformat(),
'time': d.time().isoformat()[:5]
}

def deserialize_last_login(self, source, field_name):
def deserialize_date_joined(self, source, field_name):
try:
return source[field_name]['iso']
except KeyError:
Expand All @@ -34,12 +33,12 @@ class Elasticsearch(EsIndexable.Elasticsearch):
doc_type = 'test-doc-type'
mappings = {
"username": {"index": "not_analyzed"},
"last_login": {"type": "object",
"properties": {
"iso": {"type": "date"},
"date": {"type": "string"},
"time": {"type": "string"}
}}
"date_joined": {"type": "object",
"properties": {
"iso": {"type": "date"},
"date": {"type": "string"},
"time": {"type": "string"}
}}
}
serializer_class = TestModelESSerializer

Expand Down
32 changes: 24 additions & 8 deletions django_elasticsearch/tests/test_indexable.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
import json as json_serializer

from elasticsearch import NotFoundError

from django.test import TestCase
Expand All @@ -7,6 +9,7 @@
from django_elasticsearch.managers import es_client
from django_elasticsearch.tests.utils import withattrs
from django_elasticsearch.tests.models import TestModel
from django_elasticsearch.tests.models import TestModelESSerializer
from django_elasticsearch.serializers import ModelJsonSerializer


Expand All @@ -29,18 +32,27 @@ def tearDown(self):
super(EsIndexableTestCase, self).tearDown()
es_client.indices.delete(index=TestModel.es.get_index())

def test_serialize(self):
def _serialize(self):
json = self.instance.es.serialize()
# Checking one by one, different types of fields
self.assertIn('"id": %d' % self.instance.id, json)
self.assertIn('"first_name": "woot"', json)
self.assertIn('"last_name": "foo"', json)
self.assertIn('"date_joined": "%s"' % self.instance.date_joined.isoformat(), json)

return json

def test_serializer(self):
json = self._serialize()
s = self.instance.es.serializer.serialize_date_joined(self.instance, 'date_joined')
self.assertIn('"date_joined": %s' % json_serializer.dumps(s), json)

@withattrs(TestModel.Elasticsearch, 'serializer_class',
'django_elasticsearch.serializers.ModelJsonSerializer')
def test_dynamic_serializer_import(self):
self.test_serialize()
self.instance.es.serializer = None # reset cached property
json = self._serialize()
self.instance.es.serializer = None # reset cached property
self.assertIn('"date_joined": "%s"' % self.instance.date_joined.isoformat(), json)

def test_deserialize(self):
instance = TestModel.es.deserialize({'username':'test'})
Expand Down Expand Up @@ -126,7 +138,6 @@ def test_custom_mapping(self):
}
}
# reset cache on _fields
TestModel.es._fields = None
self.assertEqual(expected, TestModel.es.make_mapping())

@withattrs(TestModel.Elasticsearch, 'completion_fields', ['first_name'])
Expand All @@ -140,17 +151,22 @@ def test_auto_completion(self):

@withattrs(TestModel.Elasticsearch, 'fields', ['username', 'date_joined'])
def test_get_mapping(self):
TestModel.es._mapping = None
TestModel.es.flush()
TestModel.es.do_update()

expected = {
'username': {u'index': u'not_analyzed', u'type': u'string'},
'date_joined': {u'type': u'date', u'format': u'dateOptionalTime'}
u'username': {u'index': u'not_analyzed', u'type': u'string'},
u'date_joined': {u'properties': {
u'iso': {u'format': u'dateOptionalTime', u'type': u'date'},
u'date': {u'type': u'string'},
u'time': {u'type': u'string'}
}}
}

# reset the eventual cache on the Model mapping
TestModel.es._mapping = None
# Reset the eventual cache on the Model mapping
mapping = TestModel.es.get_mapping()
TestModel.es._mapping = None
self.assertEqual(expected, mapping)

def test_get_settings(self):
Expand Down
19 changes: 8 additions & 11 deletions django_elasticsearch/tests/test_qs.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,10 @@ def setUp(self):
last_login=datetime.now() + timedelta(seconds=3),
date_joined=datetime.now() + timedelta(seconds=3))

# django 1.7 seems to handle settings differently than previous version
# which make the override of ELASTICSEARCH_AUTO_INDEX actually work
if django.VERSION[1] <= 7:
self.t1.es.do_index()
self.t2.es.do_index()
self.t3.es.do_index()
self.t4.es.do_index()
self.t1.es.do_index()
self.t2.es.do_index()
self.t3.es.do_index()
self.t4.es.do_index()

TestModel.es.do_update()

Expand Down Expand Up @@ -205,23 +202,23 @@ def test_isnull_lookup(self):
self.assertFalse(self.t1 in contents)

def test_sub_object_lookup(self):
qs = TestModel.es.all().filter(last_login__iso=self.t1.last_login)
qs = TestModel.es.all().filter(date_joined__iso=self.t1.date_joined)
contents = qs.deserialize()
self.assertEqual(qs.count(), 1)
self.assertTrue(self.t1 in contents)

qs = TestModel.es.all().filter(last_login__iso__isnull=False)
qs = TestModel.es.all().filter(date_joined__iso__isnull=False)
contents = qs.deserialize()
self.assertEqual(qs.count(), 4)

def test_sub_object_nested_lookup(self):
qs = TestModel.es.all().filter(last_login__iso=self.t1.last_login)
qs = TestModel.es.all().filter(date_joined__iso=self.t1.date_joined)
contents = qs.deserialize()
self.assertTrue(qs.count(), 1)
self.assertTrue(self.t1 in contents)

def test_filter_date_range(self):
qs = TestModel.es.queryset.filter(date_joined__gte=self.t2.date_joined)
qs = TestModel.es.queryset.filter(date_joined__iso__gte=self.t2.date_joined.isoformat())
contents = qs.deserialize()
self.assertTrue(self.t1 not in contents)
self.assertTrue(self.t2 in contents)
Expand Down
5 changes: 1 addition & 4 deletions django_elasticsearch/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import json

from django.test import TestCase
from django.test.utils import override_settings

from elasticsearch import TransportError

Expand Down Expand Up @@ -51,10 +50,8 @@ def test_list_view(self):
self._test_list_view()

def test_fallback_list_view(self):
# Note: in this case views responses don't match because i'm lazy
with mock.patch('django_elasticsearch.client.es_client.search') as mock_search:
with mock.patch('django_elasticsearch.query.EsQueryset.do_search') as mock_search:
mock_search.side_effect = TransportError()

response = self.client.get('/tests/')
content = json.loads(response.content)
self.assertEqual(len(content), 1)
Expand Down
15 changes: 8 additions & 7 deletions django_elasticsearch/tests/urls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from django.conf.urls import url
from django.conf.urls import patterns

import rest_framework

from django_elasticsearch.tests.models import TestModel
from django_elasticsearch.views import ElasticsearchListView
from django_elasticsearch.views import ElasticsearchDetailView
from django_elasticsearch.contrib.restframework import AutoCompletionMixin
from django_elasticsearch.contrib.restframework import IndexableModelMixin


class TestDetailView(ElasticsearchDetailView):
Expand All @@ -20,16 +24,13 @@ class TestListView(ElasticsearchListView):
url(r'^tests/$', TestListView.as_view()),
)

try:

if int(rest_framework.VERSION.split('.')[0]) < 3:
# TODO: make it work with rest framework 3
from rest_framework.viewsets import ModelViewSet
from rest_framework.routers import DefaultRouter

from django_elasticsearch.contrib.restframework import AutoCompletionMixin
from django_elasticsearch.contrib.restframework import IndexableModelMixin
except ImportError:
pass
else:
class TestViewSet(AutoCompletionMixin,IndexableModelMixin, ModelViewSet):
class TestViewSet(AutoCompletionMixin, IndexableModelMixin, ModelViewSet):
model = TestModel
filter_fields = ('username',)
ordering_fields = ('id',)
Expand Down
8 changes: 4 additions & 4 deletions django_elasticsearch/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from django.http import Http404
from django.http import HttpResponse
from django.views.generic import View
from django.views.generic.list import BaseListView
from django.views.generic.detail import BaseDetailView
from django.views.generic import ListView
from django.views.generic import DetailView
from django.core import serializers

from elasticsearch import NotFoundError
Expand Down Expand Up @@ -35,7 +35,7 @@ def get_queryset(self):
return self.queryset or self.model.es.all()


class ElasticsearchListView(ElasticsearchView, BaseListView):
class ElasticsearchListView(ElasticsearchView, ListView):

def get(self, context, *args, **kwargs):
qs = self.get_queryset()
Expand All @@ -57,7 +57,7 @@ def get(self, context, *args, **kwargs):
return HttpResponse(content, content_type='application/json')


class ElasticsearchDetailView(ElasticsearchView, BaseDetailView):
class ElasticsearchDetailView(ElasticsearchView, DetailView):

def serialize(self, qs):
s = super(ElasticsearchDetailView, self).serialize(qs)
Expand Down
9 changes: 5 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ You can also use the ```MyModel.es.check_cluster()``` method which returns True
TESTS
=====
django-elasticsearch has a 92% test coverage, and tests pass for django 1.4 to 1.7.
Django-elasticsearch has a 92% test coverage, and tests pass for django 1.4 to 1.8.
```
$ cd test_project
Expand All @@ -312,12 +312,13 @@ $ pip install -r requirements.txt # tests requirements
$ python manage.py test django_elasticsearch
```
**Note**:
To test with a older version of django, simply install it with, for example, ```pip install django==1.4.5``` and run ```python manage.py test django_elasticsearch```.
**Notes**:
* To test with a older version of django, simply install it with, for example, ```pip install django==1.4.5``` and run ```python manage.py test django_elasticsearch```.
* django-restframework version 3 is required for django >1.8, but since the api changed a lot, it's not working right now.
TODO
====
* contrib.restframework 3.0 (django 1.8) & tests
* async indexation example (with celery?)
* advanced docs / docstrings
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="django-elasticsearch",
version="0.2",
version="0.3",
description="Simple wrapper around py-elasticsearch to index/search a django Model.",
author="Robin Tissot",
url="https://github.com/liberation/django_elasticsearch",
Expand Down
6 changes: 5 additions & 1 deletion test_project/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#
# django>=1.8, <1.9
django>=1.7, <1.8
# django>=1.4, <1.5
# django>=1.6, <1.7

djangorestframework>=2.4, <3.0 # for django<1.8
# djangorestframework>=3.0, <4.0 # for django>=1.8

# dev tools
mock
six
django-filter
djangorestframework==2.4
django-extensions
Loading

0 comments on commit 53cb5ee

Please sign in to comment.