Skip to content

Commit

Permalink
examples integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Mar 22, 2024
1 parent 4b7e9fb commit 38cd862
Show file tree
Hide file tree
Showing 35 changed files with 418 additions and 63 deletions.
13 changes: 10 additions & 3 deletions examples/alias_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
will have index set to the concrete index whereas the class refers to the
alias.
"""
import os
import asyncio
from datetime import datetime
from fnmatch import fnmatch

Expand Down Expand Up @@ -125,9 +125,9 @@ def migrate(move_data=True, update_alias=True):
)


if __name__ == "__main__":
def main():
# initiate the default connection to elasticsearch
connections.create_connection(hosts=[os.environ["ELASTICSEARCH_URL"]])
connections.create_connection(hosts=["http://localhost:9200"])

# create the empty index
setup()
Expand All @@ -143,3 +143,10 @@ def migrate(move_data=True, update_alias=True):

# create new index
migrate()

# close the connection
connections.get_connection().close()


if __name__ == "__main__":
asyncio.run(main())
7 changes: 3 additions & 4 deletions examples/async/parent_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,14 @@ def search_answers(self):
s = s.params(routing=self.meta.id)
return s

def get_answers(self):
async def get_answers(self):
"""
Get answers either from inner_hits already present or by searching
elasticsearch.
"""
if "inner_hits" in self.meta and "answer" in self.meta.inner_hits:
return self.meta.inner_hits.answer.hits
return list(self.search_answers())
return [a async for a in self.search_answers()]

async def save(self, **kwargs):
self.question_answer = "question"
Expand All @@ -188,8 +188,7 @@ def _matches(cls, hit):
def search(cls, **kwargs):
return cls._index.search(**kwargs).exclude("term", question_answer="question")

@property
async def question(self):
async def get_question(self):
# cache question in self.meta
# any attributes set on self would be interpretted as fields
if "question" not in self.meta:
Expand Down
12 changes: 6 additions & 6 deletions examples/async/percolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@

from elasticsearch_dsl import (
AsyncDocument,
AsyncSearch,
Keyword,
Percolator,
Q,
Search,
Text,
async_connections,
)
Expand All @@ -40,22 +40,22 @@ class BlogPost(AsyncDocument):
class Index:
name = "test-blogpost"

def add_tags(self):
async def add_tags(self):
# run a percolation to automatically tag the blog post.
s = Search(index="test-percolator")
s = AsyncSearch(index="test-percolator")
s = s.query(
"percolate", field="query", index=self._get_index(), document=self.to_dict()
)

# collect all the tags from matched percolators
for percolator in s:
async for percolator in s:
self.tags.extend(percolator.tags)

# make sure tags are unique
self.tags = list(set(self.tags))

async def save(self, **kwargs):
self.add_tags()
await self.add_tags()
return await super().save(**kwargs)


Expand All @@ -82,7 +82,7 @@ class Index:
async def setup():
# create the percolator index if it doesn't exist
if not await PercolatorDoc._index.exists():
PercolatorDoc.init()
await PercolatorDoc.init()

# register a percolation query looking for documents about python
await PercolatorDoc(
Expand Down
10 changes: 9 additions & 1 deletion examples/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
that does ascii folding.
"""

import asyncio
import os
from itertools import permutations

Expand Down Expand Up @@ -72,7 +73,7 @@ class Index:
settings = {"number_of_shards": 1, "number_of_replicas": 0}


if __name__ == "__main__":
def main():
# initiate the default connection to elasticsearch
connections.create_connection(hosts=[os.environ["ELASTICSEARCH_URL"]])

Expand All @@ -97,3 +98,10 @@ class Index:
# print out all the options we got
for option in response.suggest.auto_complete[0].options:
print("%10s: %25s (%d)" % (text, option._source.name, option._score))

# close the connection
connections.get_connection().close()


if __name__ == "__main__":
asyncio.run(main())
13 changes: 11 additions & 2 deletions examples/composite_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.

import asyncio
import os

from elasticsearch_dsl import A, Search, connections
Expand All @@ -36,15 +37,16 @@ def run_search(**kwargs):

response = run_search()
while response.aggregations.comp.buckets:
yield from response.aggregations.comp.buckets
for b in response.aggregations.comp.buckets:
yield b
if "after_key" in response.aggregations.comp:
after = response.aggregations.comp.after_key
else:
after = response.aggregations.comp.buckets[-1].key
response = run_search(after=after)


if __name__ == "__main__":
def main():
# initiate the default connection to elasticsearch
connections.create_connection(hosts=[os.environ["ELASTICSEARCH_URL"]])

Expand All @@ -57,3 +59,10 @@ def run_search(**kwargs):
"File %s has been modified %d times, first seen at %s."
% (b.key.files, b.doc_count, b.first_seen.value_as_string)
)

# close the connection
connections.get_connection().close()


if __name__ == "__main__":
asyncio.run(main())
17 changes: 13 additions & 4 deletions examples/parent_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
particular parent
"""
import asyncio
import os
from datetime import datetime

Expand Down Expand Up @@ -165,7 +166,7 @@ def get_answers(self):
"""
if "inner_hits" in self.meta and "answer" in self.meta.inner_hits:
return self.meta.inner_hits.answer.hits
return list(self.search_answers())
return [a for a in self.search_answers()]

def save(self, **kwargs):
self.question_answer = "question"
Expand All @@ -187,8 +188,7 @@ def _matches(cls, hit):
def search(cls, **kwargs):
return cls._index.search(**kwargs).exclude("term", question_answer="question")

@property
def question(self):
def get_question(self):
# cache question in self.meta
# any attributes set on self would be interpretted as fields
if "question" not in self.meta:
Expand All @@ -209,7 +209,7 @@ def setup():
index_template.save()


if __name__ == "__main__":
def main():
# initiate the default connection to elasticsearch
connections.create_connection(hosts=[os.environ["ELASTICSEARCH_URL"]])

Expand Down Expand Up @@ -244,3 +244,12 @@ def setup():
)
question.save()
answer = question.add_answer(honza, "Just use `elasticsearch-py`!")

# close the connection
connections.get_connection().close()

return answer


if __name__ == "__main__":
asyncio.run(main())
10 changes: 9 additions & 1 deletion examples/percolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.

import asyncio
import os

from elasticsearch_dsl import (
Expand Down Expand Up @@ -91,8 +92,15 @@ def setup():
).save(refresh=True)


if __name__ == "__main__":
def main():
# initiate the default connection to elasticsearch
connections.create_connection(hosts=[os.environ["ELASTICSEARCH_URL"]])

setup()

# close the connection
connections.get_connection().close()


if __name__ == "__main__":
asyncio.run(main())
16 changes: 16 additions & 0 deletions tests/test_integration/test_examples/_async/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
1 change: 1 addition & 0 deletions tests/test_integration/test_examples/_async/completion.py
1 change: 1 addition & 0 deletions tests/test_integration/test_examples/_async/percolate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from . import alias_migration
from .alias_migration import ALIAS, PATTERN, BlogPost, migrate


async def test_alias_migration(async_write_client):
# create the index
await alias_migration.setup()

# verify that template, index, and alias has been set up
assert await async_write_client.indices.exists_template(name=ALIAS)
assert await async_write_client.indices.exists(index=PATTERN)
assert await async_write_client.indices.exists_alias(name=ALIAS)

indices = await async_write_client.indices.get(index=PATTERN)
assert len(indices) == 1
index_name, _ = indices.popitem()

# which means we can now save a document
with open(__file__) as f:
bp = BlogPost(
_id=0,
title="Hello World!",
tags=["testing", "dummy"],
content=f.read(),
)
await bp.save(refresh=True)

assert await BlogPost.search().count() == 1

# _matches work which means we get BlogPost instance
bp = (await BlogPost.search().execute())[0]
assert isinstance(bp, BlogPost)
assert not bp.is_published()
assert "0" == bp.meta.id

# create new index
await migrate()

indices = await async_write_client.indices.get(index=PATTERN)
assert 2 == len(indices)
alias = await async_write_client.indices.get(index=ALIAS)
assert 1 == len(alias)
assert index_name not in alias

# data has been moved properly
assert await BlogPost.search().count() == 1

# _matches work which means we get BlogPost instance
bp = (await BlogPost.search().execute())[0]
assert isinstance(bp, BlogPost)
assert "0" == bp.meta.id
34 changes: 34 additions & 0 deletions tests/test_integration/test_examples/_async/test_completion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.


from .completion import Person


async def test_person_suggests_on_all_variants_of_name(async_write_client):
await Person.init(using=async_write_client)

await Person(name="Honza Král", popularity=42).save(refresh=True)

s = Person.search().suggest("t", "kra", completion={"field": "suggest"})
response = await s.execute()

opts = response.suggest.t[0].options

assert 1 == len(opts)
assert opts[0]._score == 42
assert opts[0]._source.name == "Honza Král"
Loading

0 comments on commit 38cd862

Please sign in to comment.