-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Search tests #150
Closed
Closed
Search tests #150
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
cc3c31e
Add search functionlity to python app, add few search tests
jeanleonov 862cc6b
Initial SearchAPI unit tests
scragraham 5576bc7
Fix date query unittest to correctly expect one document:
scragraham 4dbfb90
Make tests independent of each other
scragraham 98061e5
cleanup unused code
scragraham 3607ed4
- Changed cleanup handler to delete from an index passed and list of …
scragraham 97fd49b
SearchAPI Tests cleanup
scragraham 59e043d
- Added search.NumberField tests
scragraham 3126ba1
- Updated hawkeye_baseline_python.csv to account for new tests.
scragraham File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,28 @@ | ||
#!/bin/bash | ||
|
||
JAVA_SDK_VERSION=1.8.4 | ||
JAVA_SDK_ZIP=appengine-java-sdk-${JAVA_SDK_VERSION}.zip | ||
SDK_URL="http://s3.amazonaws.com/appscale-build/${JAVA_SDK_ZIP}" | ||
|
||
cd ../../ | ||
if [ -e ${HOME}/${JAVA_SDK_ZIP} ]; then | ||
cp ${HOME}/${JAVA_SDK_ZIP} . | ||
else | ||
wget http://googleappengine.googlecode.com/files/${JAVA_SDK_ZIP} | ||
if ! wget ${SDK_URL}; then | ||
echo "Failed to retrieve SDK from ${SDK_URL}, exiting script" | ||
cd - | ||
exit 1 | ||
fi | ||
fi | ||
|
||
echo "Extracting ${JAVA_SDK_ZIP}" | ||
unzip -q ${JAVA_SDK_ZIP} | ||
rm ${JAVA_SDK_ZIP} | ||
echo "Extracting ${JAVA_SDK_ZIP} to ${PWD}" | ||
|
||
if ! unzip -q ${JAVA_SDK_ZIP}; then | ||
echo "Failed to unzip SDK correctly, please see errors above" | ||
rm -f ${JAVA_SDK_ZIP} | ||
cd - | ||
exit 1 | ||
fi | ||
|
||
rm -f ${JAVA_SDK_ZIP} | ||
cd - |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import json | ||
import datetime | ||
import logging | ||
import wsgiref | ||
|
||
import webapp2 | ||
|
||
from google.appengine.api.search import search | ||
from google.appengine.api.search.search import QueryOptions, ScoredDocument, Query | ||
from google.appengine.ext import webapp | ||
|
||
field_type_dict = {'text':search.TextField, | ||
'html':search.HtmlField, | ||
'atom':search.AtomField, | ||
'number':search.NumberField, | ||
'date':search.DateField} | ||
|
||
def get_field(field_name): | ||
return field_type_dict[field_name] | ||
|
||
def render_doc(document): | ||
""" | ||
Generates JSON-compatible object from object of type search.Document | ||
All fields are expected to be TextField for now | ||
:param document: document to render | ||
:type document: search.Document | ||
:return: dict {<field_name>: <string_repr_of_value>} | ||
""" | ||
if not document: | ||
return None | ||
document_dict = { | ||
field.name: unicode(field.value) for field in document.fields | ||
} | ||
# Pull over document id as it isn't included in fields. | ||
document_dict['id'] = document.doc_id | ||
|
||
if isinstance(document, ScoredDocument): | ||
document_dict["_sort_scores"] = document.sort_scores | ||
return document_dict | ||
|
||
|
||
def parse_doc(raw_document): | ||
""" | ||
Builds object of type search.Document from dict | ||
Only TextFields are supported for now | ||
:param raw_document: {<field_name>: <text_field_value>} | ||
:return: search.Document | ||
""" | ||
fields = [] | ||
# make sure fields exists? | ||
for f in raw_document.get('fields'): | ||
|
||
field = get_field(f['type']) # get class by simple name: text,atom | ||
if f['type'] in ['text','html']: | ||
# text/html has a lang field, lang should be a two character | ||
# specifier as required by the sdk. | ||
fields.append(field(f['name'], | ||
f['value'], | ||
f['lang'] if 'lang' in f else 'en')) | ||
elif f['type'] == 'date': | ||
# for date field we need to convert to a datetime | ||
fields.append(field(f['name'], | ||
datetime.datetime.strptime(f['value'], '%Y-%m-%d'))) | ||
else: | ||
# All other fields just have a name/value pair. | ||
fields.append(field(f['name'], | ||
f['value'])) | ||
|
||
return search.Document( | ||
doc_id=raw_document.get('id'), | ||
fields=fields | ||
) | ||
|
||
|
||
|
||
class PutDocumentsHandler(webapp2.RequestHandler): | ||
|
||
def post(self): | ||
payload = json.loads(self.request.body) | ||
index = payload['index'] | ||
raw_documents = payload['documents'] | ||
documents = [parse_doc(raw_doc) for raw_doc in raw_documents] | ||
put_results = search.Index(name=index).put(documents) | ||
response = {'document_ids': [result.id for result in put_results]} | ||
self.response.headers['Content-Type'] = 'application/json' | ||
self.response.out.write(json.dumps(response)) | ||
|
||
|
||
class GetDocumentHandler(webapp2.RequestHandler): | ||
|
||
def post(self): | ||
payload = json.loads(self.request.body) | ||
index = payload['index'] | ||
doc_id = payload['id'] | ||
document = search.Index(name=index).get(doc_id) | ||
response = {'document': render_doc(document)} | ||
self.response.headers['Content-Type'] = 'application/json' | ||
self.response.out.write(json.dumps(response)) | ||
|
||
|
||
class GetDocumentsRangeHandler(webapp2.RequestHandler): | ||
|
||
def post(self): | ||
payload = json.loads(self.request.body) | ||
index = payload['index'] | ||
start_id = payload['start_id'] | ||
limit = payload.get('limit') | ||
index = search.Index(name=index) | ||
documents = index.get_range(start_id=start_id, limit=limit) | ||
response = {'documents': [render_doc(document) for document in documents]} | ||
self.response.headers['Content-Type'] = 'application/json' | ||
self.response.out.write(json.dumps(response)) | ||
|
||
|
||
class SearchDocumentsHandler(webapp2.RequestHandler): | ||
|
||
def post(self): | ||
payload = json.loads(self.request.body) | ||
index = payload['index'] | ||
query = payload['query'] | ||
cursor = payload.get('cursor') | ||
limit = payload.get('limit', 20) | ||
index = search.Index(name=index) | ||
query_options = QueryOptions(limit=limit, cursor=cursor) | ||
result = index.search(Query(query, options=query_options)) | ||
response = {'documents': [render_doc(document) for document in result], | ||
'cursor': result.cursor} | ||
self.response.headers['Content-Type'] = 'application/json' | ||
self.response.out.write(json.dumps(response)) | ||
|
||
|
||
class CleanUpHandler(webapp2.RequestHandler): | ||
|
||
def post(self): | ||
payload = json.loads(self.request.body) | ||
document_ids = payload['document_ids'] | ||
index = payload['index'] | ||
idx = search.Index(name=index) | ||
|
||
idx.delete(document_ids) | ||
idx.delete_schema() | ||
|
||
urls = [ | ||
('/python/search/put', PutDocumentsHandler), | ||
('/python/search/get', GetDocumentHandler), | ||
('/python/search/get-range', GetDocumentsRangeHandler), | ||
('/python/search/search', SearchDocumentsHandler), | ||
('/python/search/clean-up', CleanUpHandler), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though these functions (
render_doc
andparse_doc
) are parts of initial branch, they need to be reworked before going to master.As field type is crucial in Search API logic, it need to be present in data model used in tests.
For handling types and multivalued fields, I'd suggest to use structure like one is used in search.Document:
rank
andlanguage
can be skipped for now.Having field with name
field1
5 times with 3 different types is allowed by Search API so using list of fields instead of dict is only way we can go.