Skip to content

Commit

Permalink
Add support to test multiple graphs - still need to improve test cove…
Browse files Browse the repository at this point in the history
…rage, remove code duplicated and update docs
  • Loading branch information
tatiana committed May 26, 2014
1 parent 7b2ae02 commit df95100
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 41 deletions.
196 changes: 156 additions & 40 deletions estester/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,7 @@ def _pre_setup(self):
"""
if self.reset_index:
self.delete_index()

self.create_index()

#if self.settings:
# self.load_settings()

#if self.mappings:
# self.load_mappings()

self.load_fixtures()

def _post_teardown(self):
Expand Down Expand Up @@ -125,45 +117,167 @@ def create_index(self):
json_data = json.dumps(data)
response = requests.put(url, proxies=self.proxies, data=json_data)

def load_mappings(self):
def load_fixtures(self):
"""
Use the following class attributes:
index: name of the index (default: sample.test)
host: ElasticSearch host (default: http://localhost:9200/)
mapping: dictionary containing type mappings (default: {})
fixtures: list of items to be loaded (default: [])
timeout: time in seconds to wait index load (default: 5s)
Example of fixtures:
[
{
"type": "book",
"id": "1",
"body": {"title": "The Hitchhiker's Guide to the Galaxy"}
},
{
"type": "book",
"id": "2",
"body": {"title": "The Restaurant at the End of the Universe"}
}
]
And load mappings to existent index.
Each item of the fixtures list represents a document at ElasticSearch
and must contain:
type: type of the document
id: unique identifier
body: json with fields of values of document
"""
for doc_type, type_mapping in self.mappings.items():
url = "{0}{1}/{2}/_mapping"
url = url.format(self.host, self.index, doc_type)
for doc in self.fixtures:
doc_type = urllib.quote_plus(doc["type"])
doc_id = urllib.quote_plus(doc["id"])
doc_body = doc["body"]
url = "{0}{1}/{2}/{3}"
url = url.format(self.host, self.index, doc_type, doc_id)
response = requests.put(
url,
data=json.dumps({doc_type: type_mapping}),
data=json.dumps(doc_body),
proxies=self.proxies)
if not response.status_code in [200, 201]:
raise ElasticSearchException(response.text)
time.sleep(self.timeout)
# http://0.0.0.0:9200/sample.test/_search

def load_settings(self):
def delete_index(self):
"""
Use the following class attributes:
index: name of the index (default: sample.test)
host: ElasticSearch host (default: http://localhost:9200/)
mapping: dictionary containing type mappings (default: {})
Deletes test index. Uses class attribute:
index: name of the index to be deleted
"""
url = "{0}{1}/".format(self.host, self.index)
requests.delete(url, proxies=self.proxies)

And load mappings to existent index.
def search(self, query=None):
"""
url = "{0}{1}/_close".format(self.host, self.index)
response = requests.post(url, proxies=self.proxies)
Run a search <query> (JSON) and returns the JSON response.
"""
url = "{0}{1}/_search".format(self.host, self.index)
query = {} if query is None else query
response = requests.post(
url,
data=json.dumps(query),
proxies=self.proxies)
return json.loads(response.text)

url = "{0}{1}/_settings"
url = url.format(self.host, self.index)
response = requests.put(
def tokenize(self, text, analyzer):
"""
Run <analyzer> on text and returns a dict containing the tokens.
"""
url = "{0}{1}/_analyze".format(self.host, self.index)
if analyzer != "default":
url += "?analyzer={0}".format(analyzer)
response = requests.post(
url,
data=json.dumps(self.settings),
data=json.dumps(text),
proxies=self.proxies)
url = "{0}{1}/_open".format(self.host, self.index)
response = requests.post(url, proxies=self.proxies)
return json.loads(response.text)

def load_fixtures(self):

class MultipleIndexesQueryTestCase(ElasticSearchQueryTestCase):
"""
Extends unittest.TestCase (estester.ElasticSearchQueryTestCase).
Allows testing ElasticSearch queries in multiple indexes.
Same:
- timeout
- proxies
- host
- reset_index
Main difference:
- index
- mappings
- settings
Are replaced by:
data = {
"index.name": {
"mappings": {}
"settings": {}
"fixtures": []
}
}
"""

data = {}

def _pre_setup(self):
"""
Load self.fixtures to the ElasticSearch index. Read load_fixtures
for more information.
Uses the following class attributes:
reset_index: delete index before loading data (default: True)
"""
for index_name, index in self.data.items():
if self.reset_index:
self.delete_index(index_name)
settings = index.get("settings", {})
mappings = index.get("mappings", {})
fixtures = index.get("fixtures", {})
self.create_index(index_name, settings, mappings)
self.load_fixtures(index_name, fixtures)

def _post_teardown(self):
"""
Clear up ElasticSearch index, if reset_index is True.
Uses the following class attributes:
index: name of the index (default: sample.test)
host: ElasticSearch host (default: http://localhost:9200/)
reset_index: delete index after running tests (default: True)
"""
for index_name, index in self.data.items():
if self.reset_index:
self.delete_index(index_name)

def create_index(self, index_name="", settings="", mappings=""):
"""
Use the following class attributes:
index: name of the index (default: sample.test)
host: ElasticSearch host (default: http://localhost:9200/)
settings: used to define analyzers (optional) (i)
mappings: attribute specific mappings according to types
To create an empty index in ElasticSearch.
(i) http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/
configuring-analyzers.html
"""
url = "{0}{1}/"
index = index_name or self.index
url = url.format(self.host, index)
data = {}
if self.mappings:
data["mappings"] = mappings or self.mappings
if self.settings:
data["settings"] = settings or self.settings
json_data = json.dumps(data)
response = requests.put(url, proxies=self.proxies, data=json_data)

def load_fixtures(self, index_name="", fixtures=""):
"""
Use the following class attributes:
index: name of the index (default: sample.test)
Expand Down Expand Up @@ -191,12 +305,14 @@ def load_fixtures(self):
id: unique identifier
body: json with fields of values of document
"""
for doc in self.fixtures:
index = index_name or self.index
fixtures = fixtures or self.fixtures
for doc in fixtures:
doc_type = urllib.quote_plus(doc["type"])
doc_id = urllib.quote_plus(doc["id"])
doc_body = doc["body"]
url = "{0}{1}/{2}/{3}"
url = url.format(self.host, self.index, doc_type, doc_id)
url = url.format(self.host, index, doc_type, doc_id)
response = requests.put(
url,
data=json.dumps(doc_body),
Expand All @@ -206,35 +322,35 @@ def load_fixtures(self):
time.sleep(self.timeout)
# http://0.0.0.0:9200/sample.test/_search

def delete_index(self):
def delete_index(self, index_name=""):
"""
Deletes test index. Uses class attribute:
index: name of the index to be deleted
"""
index = index_name or self.index
url = "{0}{1}/".format(self.host, self.index)
requests.delete(url, proxies=self.proxies)

def search(self, query=None):
"""
Run a search <query> (JSON) and returns the JSON response.
"""
url = "{0}{1}/_search".format(self.host, self.index)
url = "{0}/_search".format(self.host)
query = {} if query is None else query
response = requests.post(
url,
data=json.dumps(query),
proxies=self.proxies)
return json.loads(response.text)

def tokenize(self, text, analyzer):
def search_in_index(self, index, query=None):
"""
Run <analyzer> on text and returns a dict containing the tokens.
Run a search <query> (JSON) and returns the JSON response.
"""
url = "{0}{1}/_analyze".format(self.host, self.index)
if analyzer != "default":
url += "?analyzer={0}".format(analyzer)
url = "{0}/{1}/_search".format(self.host, index)
query = {} if query is None else query
response = requests.post(
url,
data=json.dumps(text),
data=json.dumps(query),
proxies=self.proxies)
return json.loads(response.text)
83 changes: 82 additions & 1 deletion tests/test_querytestcase.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest
from mock import patch
from estester import ElasticSearchQueryTestCase, ExtendedTestCase
from estester import ElasticSearchQueryTestCase, ExtendedTestCase,\
MultipleIndexesQueryTestCase


SIMPLE_QUERY = {
Expand Down Expand Up @@ -45,6 +46,86 @@ def test_default_values(self):
self.assertEqual(ESQTC.proxies, {})


class SimpleMultipleIndexesQueryTestCase(MultipleIndexesQueryTestCase):

data = {
"personal": {
"fixtures": [
{
"type": "contact",
"id": "1",
"body": {"name": "Dmitriy"}
},
{
"type": "contact",
"id": "2",
"body": {"name": "Agnessa"}
}
]
},
"professional": {
"fixtures": [
{
"type": "contact",
"id": "1",
"body": {"name": "Nikolay"}
}
]
}
}

def test_search_all_indexes(self):
response = self.search()
expected = [
{
u'_score': 1.0,
u'_type': u'contact',
u'_id': u'1',
u'_source': {u'name': u'Dmitriy'},
u'_index': u'personal'
},
{
u'_score': 1.0,
u'_type': u'contact',
u'_id': u'2',
u'_source': {u'name': u'Agnessa'},
u'_index': u'personal'
},
{
u'_score': 1.0,
u'_type': u'contact',
u'_id': u'1', u'_source': {u'name': u'Nikolay'},
u'_index': u'professional'
}
]
self.assertEqual(response["hits"]["total"], 3)
self.assertEqual(sorted(response["hits"]["hits"]), sorted(expected))

def test_search_one_index_that_has_item(self):
query = {
"query": {
"text": {
"name": "Agnessa"
}
}
}
response = self.search_in_index("personal", query)
self.assertEqual(response["hits"]["total"], 1)
expected = {u'name': u'Agnessa'}
self.assertEqual(response["hits"]["hits"][0]["_source"], expected)

def test_search_one_index_that_doesnt_have_item(self):
query = {
"query": {
"text": {
"name": "Agnessa"
}
}
}
response = self.search_in_index("professional", query)
self.assertEqual(response["hits"]["total"], 0)


class SimpleQueryTestCase(ElasticSearchQueryTestCase):

fixtures = [
Expand Down

0 comments on commit df95100

Please sign in to comment.