Added async support for helpers that are merged from opensearch-dsl-py (#329)

Signed-off-by: saimedhi <[email protected]>
This commit is contained in:
Sai Medhini Reddy Maryada
2023-03-17 12:03:46 -07:00
committed by GitHub
parent 409c883013
commit 2b9aee73a5
40 changed files with 7226 additions and 63 deletions
@@ -0,0 +1,110 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
import asyncio
import re
from datetime import datetime
import pytest
from pytest import fixture
from test_data import (
DATA,
FLAT_DATA,
TEST_GIT_DATA,
create_flat_git_index,
create_git_index,
)
from opensearchpy._async.helpers.actions import async_bulk
from opensearchpy._async.helpers.test import get_test_client
from opensearchpy.connection.async_connections import add_connection
from test_opensearchpy.test_server.test_helpers.test_document import (
Comment,
History,
PullRequest,
User,
)
pytestmark = pytest.mark.asyncio
@pytest.fixture(scope="session")
def event_loop():
loop = asyncio.get_event_loop()
yield loop
loop.close()
@fixture(scope="session")
async def client():
client = await get_test_client(verify_certs=False, http_auth=("admin", "admin"))
await add_connection("default", client)
return client
@fixture(scope="session")
async def opensearch_version(client):
info = await client.info()
print(info)
yield tuple(
int(x)
for x in re.match(r"^([0-9.]+)", info["version"]["number"]).group(1).split(".")
)
@fixture
async def write_client(client):
yield client
await client.indices.delete("test-*", ignore=404)
await client.indices.delete_template("test-template", ignore=404)
@fixture
async def data_client(client):
# create mappings
await create_git_index(client, "git")
await create_flat_git_index(client, "flat-git")
# load data
await async_bulk(client, DATA, raise_on_error=True, refresh=True)
await async_bulk(client, FLAT_DATA, raise_on_error=True, refresh=True)
yield client
await client.indices.delete("git", ignore=404)
await client.indices.delete("flat-git", ignore=404)
@fixture
def pull_request(write_client):
PullRequest.init()
pr = PullRequest(
_id=42,
comments=[
Comment(
content="Hello World!",
author=User(name="honzakral"),
created_at=datetime(2018, 1, 9, 10, 17, 3, 21184),
history=[
History(
timestamp=datetime(2012, 1, 1),
diff="-Ahoj Svete!\n+Hello World!",
)
],
),
],
created_at=datetime(2018, 1, 9, 9, 17, 3, 21184),
)
pr.save(refresh=True)
return pr
@fixture
async def setup_ubq_tests(client):
index = "test-git"
await create_git_index(client, index)
await async_bulk(client, TEST_GIT_DATA, raise_on_error=True, refresh=True)
return index
@@ -25,16 +25,13 @@
# under the License.
# Licensed to Elasticsearch B.V.under one or more agreements.
# Elasticsearch B.V.licenses this file to you under the Apache 2.0 License.
# See the LICENSE file in the project root for more information
import asyncio
import pytest
from mock import MagicMock, patch
from opensearchpy import TransportError, helpers
from opensearchpy import TransportError
from opensearchpy._async.helpers import actions
from opensearchpy.helpers import BulkIndexError, ScanError
pytestmark = pytest.mark.asyncio
@@ -67,16 +64,16 @@ class FailingBulkClient(object):
class TestStreamingBulk(object):
async def test_actions_remain_unchanged(self, async_client):
actions = [{"_id": 1}, {"_id": 2}]
async for ok, item in helpers.async_streaming_bulk(
async_client, actions, index="test-index"
actions1 = [{"_id": 1}, {"_id": 2}]
async for ok, item in actions.async_streaming_bulk(
async_client, actions1, index="test-index"
):
assert ok
assert [{"_id": 1}, {"_id": 2}] == actions
assert [{"_id": 1}, {"_id": 2}] == actions1
async def test_all_documents_get_inserted(self, async_client):
docs = [{"answer": x, "_id": x} for x in range(100)]
async for ok, item in helpers.async_streaming_bulk(
async for ok, item in actions.async_streaming_bulk(
async_client, docs, index="test-index", refresh=True
):
assert ok
@@ -96,7 +93,7 @@ class TestStreamingBulk(object):
for x in range(100):
yield {"answer": x, "_id": x}
async for ok, item in helpers.async_streaming_bulk(
async for ok, item in actions.async_streaming_bulk(
async_client, async_gen(), index="test-index", refresh=True
):
assert ok
@@ -110,7 +107,7 @@ class TestStreamingBulk(object):
index="test-index", body={"query": {"match_all": {}}}
)
async for ok, item in helpers.async_streaming_bulk(
async for ok, item in actions.async_streaming_bulk(
async_client, sync_gen(), index="test-index", refresh=True
):
assert ok
@@ -131,7 +128,7 @@ class TestStreamingBulk(object):
await async_client.cluster.health(wait_for_status="yellow")
try:
async for ok, item in helpers.async_streaming_bulk(
async for ok, item in actions.async_streaming_bulk(
async_client, [{"a": "b"}, {"a": "c"}], index="i", raise_on_error=True
):
assert ok
@@ -148,7 +145,7 @@ class TestStreamingBulk(object):
{"_op_type": "delete", "_index": "i", "_id": 45},
{"_op_type": "update", "_index": "i", "_id": 42, "doc": {"answer": 42}},
]
async for ok, item in helpers.async_streaming_bulk(async_client, docs):
async for ok, item in actions.async_streaming_bulk(async_client, docs):
assert ok
assert not await async_client.exists(index="i", id=45)
@@ -165,7 +162,7 @@ class TestStreamingBulk(object):
results = [
x
async for x in helpers.async_streaming_bulk(
async for x in actions.async_streaming_bulk(
failing_client,
docs,
raise_on_exception=False,
@@ -200,7 +197,7 @@ class TestStreamingBulk(object):
]
results = [
x
async for x in helpers.async_streaming_bulk(
async for x in actions.async_streaming_bulk(
failing_client,
docs,
raise_on_exception=False,
@@ -231,7 +228,7 @@ class TestStreamingBulk(object):
]
results = [
x
async for x in helpers.async_streaming_bulk(
async for x in actions.async_streaming_bulk(
failing_client,
docs,
raise_on_exception=False,
@@ -258,7 +255,7 @@ class TestStreamingBulk(object):
async def streaming_bulk():
results = [
x
async for x in helpers.async_streaming_bulk(
async for x in actions.async_streaming_bulk(
failing_client,
[{"a": 42}, {"a": 39}],
raise_on_exception=True,
@@ -276,7 +273,7 @@ class TestStreamingBulk(object):
class TestBulk(object):
async def test_bulk_works_with_single_item(self, async_client):
docs = [{"answer": 42, "_id": 1}]
success, failed = await helpers.async_bulk(
success, failed = await actions.async_bulk(
async_client, docs, index="test-index", refresh=True
)
@@ -289,7 +286,7 @@ class TestBulk(object):
async def test_all_documents_get_inserted(self, async_client):
docs = [{"answer": x, "_id": x} for x in range(100)]
success, failed = await helpers.async_bulk(
success, failed = await actions.async_bulk(
async_client, docs, index="test-index", refresh=True
)
@@ -302,7 +299,7 @@ class TestBulk(object):
async def test_stats_only_reports_numbers(self, async_client):
docs = [{"answer": x} for x in range(100)]
success, failed = await helpers.async_bulk(
success, failed = await actions.async_bulk(
async_client, docs, index="test-index", refresh=True, stats_only=True
)
@@ -320,7 +317,7 @@ class TestBulk(object):
)
await async_client.cluster.health(wait_for_status="yellow")
success, failed = await helpers.async_bulk(
success, failed = await actions.async_bulk(
async_client,
[{"a": 42}, {"a": "c", "_id": 42}],
index="i",
@@ -347,16 +344,16 @@ class TestBulk(object):
await async_client.cluster.health(wait_for_status="yellow")
with pytest.raises(BulkIndexError):
await helpers.async_bulk(async_client, [{"a": 42}, {"a": "c"}], index="i")
await actions.async_bulk(async_client, [{"a": 42}, {"a": "c"}], index="i")
async def test_ignore_error_if_raised(self, async_client):
# ignore the status code 400 in tuple
await helpers.async_bulk(
await actions.async_bulk(
async_client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=(400,)
)
# ignore the status code 400 in list
await helpers.async_bulk(
await actions.async_bulk(
async_client,
[{"a": 42}, {"a": "c"}],
index="i",
@@ -366,19 +363,19 @@ class TestBulk(object):
)
# ignore the status code 400
await helpers.async_bulk(
await actions.async_bulk(
async_client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=400
)
# ignore only the status code in the `ignore_status` argument
with pytest.raises(BulkIndexError):
await helpers.async_bulk(
await actions.async_bulk(
async_client, [{"a": 42}, {"a": "c"}], index="i", ignore_status=(444,)
)
# ignore transport error exception
failing_client = FailingBulkClient(async_client)
await helpers.async_bulk(
await actions.async_bulk(
failing_client, [{"a": 42}], index="i", ignore_status=(599,)
)
@@ -392,7 +389,7 @@ class TestBulk(object):
)
await async_client.cluster.health(wait_for_status="yellow")
success, failed = await helpers.async_bulk(
success, failed = await actions.async_bulk(
async_client,
[{"a": 42}, {"a": "c"}],
index="i",
@@ -452,7 +449,7 @@ class TestScan(object):
docs = [
doc
async for doc in helpers.async_scan(
async for doc in actions.async_scan(
async_client,
index="test_index",
query={"sort": "answer"},
@@ -473,7 +470,7 @@ class TestScan(object):
docs = [
x
async for x in helpers.async_scan(async_client, index="test_index", size=2)
async for x in actions.async_scan(async_client, index="test_index", size=2)
]
assert 100 == len(docs)
@@ -490,7 +487,7 @@ class TestScan(object):
with patch.object(async_client, "scroll", MockScroll()):
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
size=2,
@@ -505,7 +502,7 @@ class TestScan(object):
with pytest.raises(ScanError):
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
size=2,
@@ -532,7 +529,7 @@ class TestScan(object):
with patch.object(async_client, "scroll", MockScroll()):
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
size=2,
@@ -556,7 +553,7 @@ class TestScan(object):
with pytest.raises(ScanError):
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
size=2,
@@ -572,7 +569,7 @@ class TestScan(object):
with patch.object(async_client, "clear_scroll") as clear_mock:
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client, index="test_index"
)
]
@@ -581,7 +578,7 @@ class TestScan(object):
scroll_mock.assert_not_called()
clear_mock.assert_not_called()
@patch("opensearchpy._async.helpers.logger")
@patch("opensearchpy._async.helpers.actions.logger")
async def test_logger(self, logger_mock, async_client, scan_teardown):
bulk = []
for x in range(4):
@@ -592,7 +589,7 @@ class TestScan(object):
with patch.object(async_client, "scroll", MockScroll()):
_ = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
size=2,
@@ -606,7 +603,7 @@ class TestScan(object):
try:
_ = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
size=2,
@@ -635,7 +632,7 @@ class TestScan(object):
) as spy:
_ = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client, index="test_index", size=2
)
]
@@ -644,7 +641,7 @@ class TestScan(object):
spy.reset_mock()
_ = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client, index="test_index", size=2, clear_scroll=True
)
]
@@ -653,7 +650,7 @@ class TestScan(object):
spy.reset_mock()
_ = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client, index="test_index", size=2, clear_scroll=False
)
]
@@ -699,7 +696,7 @@ class TestScan(object):
) as clear_mock:
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client, index="test_index", **kwargs
)
]
@@ -739,7 +736,7 @@ class TestScan(object):
):
data = [
x
async for x in helpers.async_scan(
async for x in actions.async_scan(
async_client,
index="test_index",
headers={"not scroll": "kwargs"},
@@ -779,7 +776,7 @@ class TestReindex(object):
async def test_reindex_passes_kwargs_to_scan_and_bulk(
self, async_client, reindex_setup
):
await helpers.async_reindex(
await actions.async_reindex(
async_client,
"test_index",
"prod_index",
@@ -798,7 +795,7 @@ class TestReindex(object):
)["_source"]
async def test_reindex_accepts_a_query(self, async_client, reindex_setup):
await helpers.async_reindex(
await actions.async_reindex(
async_client,
"test_index",
"prod_index",
@@ -817,7 +814,7 @@ class TestReindex(object):
)["_source"]
async def test_all_documents_get_moved(self, async_client, reindex_setup):
await helpers.async_reindex(async_client, "test_index", "prod_index")
await actions.async_reindex(async_client, "test_index", "prod_index")
await async_client.indices.refresh()
assert await async_client.indices.exists("prod_index")
@@ -869,7 +866,7 @@ class TestParentChildReindex:
async def test_children_are_reindexed_correctly(
self, async_client, parent_reindex_setup
):
await helpers.async_reindex(async_client, "test-index", "real-index")
await actions.async_reindex(async_client, "test-index", "real-index")
assert {"question_answer": "question"} == (
await async_client.get(index="real-index", id=42)
)["_source"]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,555 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
from datetime import datetime
from ipaddress import ip_address
import pytest
from pytest import raises
from pytz import timezone
from opensearchpy import (
Binary,
Boolean,
ConflictError,
Date,
Double,
InnerDoc,
Ip,
Keyword,
Long,
MetaField,
Nested,
NotFoundError,
Object,
Q,
RankFeatures,
Text,
analyzer,
)
from opensearchpy._async.helpers.actions import aiter
from opensearchpy._async.helpers.document import AsyncDocument
from opensearchpy._async.helpers.mapping import AsyncMapping
from opensearchpy.helpers.utils import AttrList
pytestmark = pytest.mark.asyncio
snowball = analyzer("my_snow", tokenizer="standard", filter=["lowercase", "snowball"])
class User(InnerDoc):
name = Text(fields={"raw": Keyword()})
class Wiki(AsyncDocument):
owner = Object(User)
views = Long()
ranked = RankFeatures()
class Index:
name = "test-wiki"
class Repository(AsyncDocument):
owner = Object(User)
created_at = Date()
description = Text(analyzer=snowball)
tags = Keyword()
@classmethod
def search(cls):
return super(Repository, cls).search().filter("term", commit_repo="repo")
class Index:
name = "git"
class Commit(AsyncDocument):
committed_date = Date()
authored_date = Date()
description = Text(analyzer=snowball)
class Index:
name = "flat-git"
class Meta:
mapping = AsyncMapping()
class History(InnerDoc):
timestamp = Date()
diff = Text()
class Comment(InnerDoc):
content = Text()
created_at = Date()
author = Object(User)
history = Nested(History)
class Meta:
dynamic = MetaField(False)
class PullRequest(AsyncDocument):
comments = Nested(Comment)
created_at = Date()
class Index:
name = "test-prs"
class SerializationDoc(AsyncDocument):
i = Long()
b = Boolean()
d = Double()
bin = Binary()
ip = Ip()
class Index:
name = "test-serialization"
async def test_serialization(write_client):
await SerializationDoc.init()
await write_client.index(
index="test-serialization",
id=42,
body={
"i": [1, 2, "3", None],
"b": [True, False, "true", "false", None],
"d": [0.1, "-0.1", None],
"bin": ["SGVsbG8gV29ybGQ=", None],
"ip": ["::1", "127.0.0.1", None],
},
)
sd = await SerializationDoc.get(id=42)
assert sd.i == [1, 2, 3, None]
assert sd.b == [True, False, True, False, None]
assert sd.d == [0.1, -0.1, None]
assert sd.bin == [b"Hello World", None]
assert sd.ip == [ip_address("::1"), ip_address("127.0.0.1"), None]
assert sd.to_dict() == {
"b": [True, False, True, False, None],
"bin": ["SGVsbG8gV29ybGQ=", None],
"d": [0.1, -0.1, None],
"i": [1, 2, 3, None],
"ip": ["::1", "127.0.0.1", None],
}
async def test_nested_inner_hits_are_wrapped_properly(pull_request):
history_query = Q(
"nested",
path="comments.history",
inner_hits={},
query=Q("match", comments__history__diff="ahoj"),
)
s = PullRequest.search().query(
"nested", inner_hits={}, path="comments", query=history_query
)
response = await s.execute()
pr = response.hits[0]
assert isinstance(pr, PullRequest)
assert isinstance(pr.comments[0], Comment)
assert isinstance(pr.comments[0].history[0], History)
comment = pr.meta.inner_hits.comments.hits[0]
assert isinstance(comment, Comment)
assert comment.author.name == "honzakral"
assert isinstance(comment.history[0], History)
history = comment.meta.inner_hits["comments.history"].hits[0]
assert isinstance(history, History)
assert history.timestamp == datetime(2012, 1, 1)
assert "score" in history.meta
async def test_nested_inner_hits_are_deserialized_properly(pull_request):
s = PullRequest.search().query(
"nested",
inner_hits={},
path="comments",
query=Q("match", comments__content="hello"),
)
response = await s.execute()
pr = response.hits[0]
assert isinstance(pr.created_at, datetime)
assert isinstance(pr.comments[0], Comment)
assert isinstance(pr.comments[0].created_at, datetime)
async def test_nested_top_hits_are_wrapped_properly(pull_request):
s = PullRequest.search()
s.aggs.bucket("comments", "nested", path="comments").metric(
"hits", "top_hits", size=1
)
r = await s.execute()
print(r._d_)
assert isinstance(r.aggregations.comments.hits.hits[0], Comment)
async def test_update_object_field(write_client):
await Wiki.init()
w = Wiki(
owner=User(name="Honza Kral"),
_id="opensearch-py",
ranked={"test1": 0.1, "topic2": 0.2},
)
await w.save()
assert "updated" == await w.update(owner=[{"name": "Honza"}, {"name": "Nick"}])
assert w.owner[0].name == "Honza"
assert w.owner[1].name == "Nick"
w = await Wiki.get(id="opensearch-py")
assert w.owner[0].name == "Honza"
assert w.owner[1].name == "Nick"
assert w.ranked == {"test1": 0.1, "topic2": 0.2}
async def test_update_script(write_client):
await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
await w.save()
await w.update(script="ctx._source.views += params.inc", inc=5)
w = await Wiki.get(id="opensearch-py")
assert w.views == 47
async def test_update_retry_on_conflict(write_client):
await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
await w.save()
w1 = await Wiki.get(id="opensearch-py")
w2 = await Wiki.get(id="opensearch-py")
await w1.update(
script="ctx._source.views += params.inc", inc=5, retry_on_conflict=1
)
await w2.update(
script="ctx._source.views += params.inc", inc=5, retry_on_conflict=1
)
w = await Wiki.get(id="opensearch-py")
assert w.views == 52
@pytest.mark.parametrize("retry_on_conflict", [None, 0])
async def test_update_conflicting_version(write_client, retry_on_conflict):
await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
await w.save()
w1 = await Wiki.get(id="opensearch-py")
w2 = await Wiki.get(id="opensearch-py")
await w1.update(script="ctx._source.views += params.inc", inc=5)
with raises(ConflictError):
await w2.update(
script="ctx._source.views += params.inc",
inc=5,
retry_on_conflict=retry_on_conflict,
)
async def test_save_and_update_return_doc_meta(write_client):
await Wiki.init()
w = Wiki(owner=User(name="Honza Kral"), _id="opensearch-py", views=42)
resp = await w.save(return_doc_meta=True)
assert resp["_index"] == "test-wiki"
assert resp["result"] == "created"
assert resp.keys().__contains__("_id")
assert resp.keys().__contains__("_primary_term")
assert resp.keys().__contains__("_seq_no")
assert resp.keys().__contains__("_shards")
assert resp.keys().__contains__("_version")
resp = await w.update(
script="ctx._source.views += params.inc", inc=5, return_doc_meta=True
)
assert resp["_index"] == "test-wiki"
assert resp["result"] == "updated"
assert resp.keys().__contains__("_id")
assert resp.keys().__contains__("_primary_term")
assert resp.keys().__contains__("_seq_no")
assert resp.keys().__contains__("_shards")
assert resp.keys().__contains__("_version")
async def test_init(write_client):
await Repository.init(index="test-git")
assert await write_client.indices.exists(index="test-git")
async def test_get_raises_404_on_index_missing(data_client):
with raises(NotFoundError):
await Repository.get("opensearch-dsl-php", index="not-there")
async def test_get_raises_404_on_non_existent_id(data_client):
with raises(NotFoundError):
await Repository.get("opensearch-dsl-php")
async def test_get_returns_none_if_404_ignored(data_client):
assert None is await Repository.get("opensearch-dsl-php", ignore=404)
async def test_get_returns_none_if_404_ignored_and_index_doesnt_exist(data_client):
assert None is await Repository.get("42", index="not-there", ignore=404)
async def test_get(data_client):
opensearch_repo = await Repository.get("opensearch-py")
assert isinstance(opensearch_repo, Repository)
assert opensearch_repo.owner.name == "opensearch"
assert datetime(2014, 3, 3) == opensearch_repo.created_at
async def test_exists_return_true(data_client):
assert await Repository.exists("opensearch-py")
async def test_exists_false(data_client):
assert not await Repository.exists("opensearch-dsl-php")
async def test_get_with_tz_date(data_client):
first_commit = await Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
)
tzinfo = timezone("Europe/Prague")
assert (
tzinfo.localize(datetime(2014, 5, 2, 13, 47, 19, 123000))
== first_commit.authored_date
)
async def test_save_with_tz_date(data_client):
tzinfo = timezone("Europe/Prague")
first_commit = await Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
)
first_commit.committed_date = tzinfo.localize(
datetime(2014, 5, 2, 13, 47, 19, 123456)
)
await first_commit.save()
first_commit = await Commit.get(
id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="opensearch-py"
)
assert (
tzinfo.localize(datetime(2014, 5, 2, 13, 47, 19, 123456))
== first_commit.committed_date
)
COMMIT_DOCS_WITH_MISSING = [
{"_id": "0"}, # Missing
{"_id": "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"}, # Existing
{"_id": "f"}, # Missing
{"_id": "eb3e543323f189fd7b698e66295427204fff5755"}, # Existing
]
async def test_mget(data_client):
commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING)
assert commits[0] is None
assert commits[1].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"
assert commits[2] is None
assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
async def test_mget_raises_exception_when_missing_param_is_invalid(data_client):
with raises(ValueError):
await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj")
async def test_mget_raises_404_when_missing_param_is_raise(data_client):
with raises(NotFoundError):
await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise")
async def test_mget_ignores_missing_docs_when_missing_param_is_skip(data_client):
commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="skip")
assert commits[0].meta.id == "3ca6e1e73a071a705b4babd2f581c91a2a3e5037"
assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
async def test_update_works_from_search_response(data_client):
opensearch_repo = (await Repository.search().execute())[0]
await opensearch_repo.update(owner={"other_name": "opensearchpy"})
assert "opensearchpy" == opensearch_repo.owner.other_name
new_version = await Repository.get("opensearch-py")
assert "opensearchpy" == new_version.owner.other_name
assert "opensearch" == new_version.owner.name
async def test_update(data_client):
opensearch_repo = await Repository.get("opensearch-py")
v = opensearch_repo.meta.version
old_seq_no = opensearch_repo.meta.seq_no
await opensearch_repo.update(
owner={"new_name": "opensearchpy"}, new_field="testing-update"
)
assert "opensearchpy" == opensearch_repo.owner.new_name
assert "testing-update" == opensearch_repo.new_field
# assert version has been updated
assert opensearch_repo.meta.version == v + 1
new_version = await Repository.get("opensearch-py")
assert "testing-update" == new_version.new_field
assert "opensearchpy" == new_version.owner.new_name
assert "opensearch" == new_version.owner.name
assert "seq_no" in new_version.meta
assert new_version.meta.seq_no != old_seq_no
assert "primary_term" in new_version.meta
async def test_save_updates_existing_doc(data_client):
opensearch_repo = await Repository.get("opensearch-py")
opensearch_repo.new_field = "testing-save"
old_seq_no = opensearch_repo.meta.seq_no
assert "updated" == await opensearch_repo.save()
new_repo = await data_client.get(index="git", id="opensearch-py")
assert "testing-save" == new_repo["_source"]["new_field"]
assert new_repo["_seq_no"] != old_seq_no
assert new_repo["_seq_no"] == opensearch_repo.meta.seq_no
async def test_save_automatically_uses_seq_no_and_primary_term(data_client):
opensearch_repo = await Repository.get("opensearch-py")
opensearch_repo.meta.seq_no += 1
with raises(ConflictError):
await opensearch_repo.save()
async def test_delete_automatically_uses_seq_no_and_primary_term(data_client):
opensearch_repo = await Repository.get("opensearch-py")
opensearch_repo.meta.seq_no += 1
with raises(ConflictError):
await opensearch_repo.delete()
async def assert_doc_equals(expected, actual):
async for f in aiter(expected):
assert f in actual
assert actual[f] == expected[f]
async def test_can_save_to_different_index(write_client):
test_repo = Repository(description="testing", meta={"id": 42})
assert await test_repo.save(index="test-document")
await assert_doc_equals(
{
"found": True,
"_index": "test-document",
"_id": "42",
"_source": {"description": "testing"},
},
await write_client.get(index="test-document", id=42),
)
async def test_save_without_skip_empty_will_include_empty_fields(write_client):
test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42})
assert await test_repo.save(index="test-document", skip_empty=False)
await assert_doc_equals(
{
"found": True,
"_index": "test-document",
"_id": "42",
"_source": {"field_1": [], "field_2": None, "field_3": {}},
},
await write_client.get(index="test-document", id=42),
)
async def test_delete(write_client):
await write_client.create(
index="test-document",
id="opensearch-py",
body={
"organization": "opensearch",
"created_at": "2014-03-03",
"owner": {"name": "opensearch"},
},
)
test_repo = Repository(meta={"id": "opensearch-py"})
test_repo.meta.index = "test-document"
await test_repo.delete()
assert not await write_client.exists(
index="test-document",
id="opensearch-py",
)
async def test_search(data_client):
assert await Repository.search().count() == 1
async def test_search_returns_proper_doc_classes(data_client):
result = await Repository.search().execute()
opensearch_repo = result.hits[0]
assert isinstance(opensearch_repo, Repository)
assert opensearch_repo.owner.name == "opensearch"
async def test_refresh_mapping(data_client):
class Commit(AsyncDocument):
class Index:
name = "git"
await Commit._index.load_mappings()
assert "stats" in Commit._index._mapping
assert "committer" in Commit._index._mapping
assert "description" in Commit._index._mapping
assert "committed_date" in Commit._index._mapping
assert isinstance(Commit._index._mapping["committed_date"], Date)
async def test_highlight_in_meta(data_client):
commit = (
await Commit.search()
.query("match", description="inverting")
.highlight("description")
.execute()
)[0]
assert isinstance(commit, Commit)
assert "description" in commit.meta.highlight
assert isinstance(commit.meta.highlight["description"], AttrList)
assert len(commit.meta.highlight["description"]) > 0
@@ -0,0 +1,274 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
from datetime import datetime
import pytest
from opensearchpy import A, Boolean, Date, Keyword
from opensearchpy._async.helpers.document import AsyncDocument
from opensearchpy._async.helpers.faceted_search import AsyncFacetedSearch
from opensearchpy.helpers.faceted_search import (
DateHistogramFacet,
NestedFacet,
RangeFacet,
TermsFacet,
)
from test_opensearchpy.test_async.test_server.test_helpers.test_document import (
PullRequest,
)
pytestmark = pytest.mark.asyncio
class Repos(AsyncDocument):
is_public = Boolean()
created_at = Date()
class Index:
name = "git"
class Commit(AsyncDocument):
files = Keyword()
committed_date = Date()
class Index:
name = "git"
class MetricSearch(AsyncFacetedSearch):
index = "git"
doc_types = [Commit]
facets = {
"files": TermsFacet(field="files", metric=A("max", field="committed_date")),
}
@pytest.fixture(scope="session")
def commit_search_cls(opensearch_version):
interval_kwargs = {"fixed_interval": "1d"}
class CommitSearch(AsyncFacetedSearch):
index = "flat-git"
fields = (
"description",
"files",
)
facets = {
"files": TermsFacet(field="files"),
"frequency": DateHistogramFacet(
field="authored_date", min_doc_count=1, **interval_kwargs
),
"deletions": RangeFacet(
field="stats.deletions",
ranges=[("ok", (None, 1)), ("good", (1, 5)), ("better", (5, None))],
),
}
return CommitSearch
@pytest.fixture(scope="session")
def repo_search_cls(opensearch_version):
interval_type = "calendar_interval"
class RepoSearch(AsyncFacetedSearch):
index = "git"
doc_types = [Repos]
facets = {
"public": TermsFacet(field="is_public"),
"created": DateHistogramFacet(
field="created_at", **{interval_type: "month"}
),
}
def search(self):
s = super(RepoSearch, self).search()
return s.filter("term", commit_repo="repo")
return RepoSearch
@pytest.fixture(scope="session")
def pr_search_cls(opensearch_version):
interval_type = "calendar_interval"
class PRSearch(AsyncFacetedSearch):
index = "test-prs"
doc_types = [PullRequest]
facets = {
"comments": NestedFacet(
"comments",
DateHistogramFacet(
field="comments.created_at", **{interval_type: "month"}
),
)
}
return PRSearch
async def test_facet_with_custom_metric(data_client):
ms = MetricSearch()
r = await ms.execute()
dates = [f[1] for f in r.facets.files]
assert dates == list(sorted(dates, reverse=True))
assert dates[0] == 1399038439000
async def test_nested_facet(pull_request, pr_search_cls):
prs = pr_search_cls()
r = await prs.execute()
assert r.hits.total.value == 1
assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments
async def test_nested_facet_with_filter(pull_request, pr_search_cls):
prs = pr_search_cls(filters={"comments": datetime(2018, 1, 1, 0, 0)})
r = await prs.execute()
assert r.hits.total.value == 1
assert [(datetime(2018, 1, 1, 0, 0), 1, True)] == r.facets.comments
prs = pr_search_cls(filters={"comments": datetime(2018, 2, 1, 0, 0)})
r = await prs.execute()
assert not r.hits
async def test_datehistogram_facet(data_client, repo_search_cls):
rs = repo_search_cls()
r = await rs.execute()
assert r.hits.total.value == 1
assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created
async def test_boolean_facet(data_client, repo_search_cls):
rs = repo_search_cls()
r = await rs.execute()
assert r.hits.total.value == 1
assert [(True, 1, False)] == r.facets.public
value, count, selected = r.facets.public[0]
assert value is True
async def test_empty_search_finds_everything(
data_client, opensearch_version, commit_search_cls
):
cs = commit_search_cls()
r = await cs.execute()
assert r.hits.total.value == 52
assert [
("opensearchpy", 39, False),
("test_opensearchpy", 35, False),
("test_opensearchpy/test_dsl", 35, False),
("opensearchpy/query.py", 18, False),
("test_opensearchpy/test_dsl/test_search.py", 15, False),
("opensearchpy/utils.py", 14, False),
("test_opensearchpy/test_dsl/test_query.py", 13, False),
("opensearchpy/search.py", 12, False),
("opensearchpy/aggs.py", 11, False),
("test_opensearchpy/test_dsl/test_result.py", 5, False),
] == r.facets.files
assert [
(datetime(2014, 3, 3, 0, 0), 2, False),
(datetime(2014, 3, 4, 0, 0), 1, False),
(datetime(2014, 3, 5, 0, 0), 3, False),
(datetime(2014, 3, 6, 0, 0), 3, False),
(datetime(2014, 3, 7, 0, 0), 9, False),
(datetime(2014, 3, 10, 0, 0), 2, False),
(datetime(2014, 3, 15, 0, 0), 4, False),
(datetime(2014, 3, 21, 0, 0), 2, False),
(datetime(2014, 3, 23, 0, 0), 2, False),
(datetime(2014, 3, 24, 0, 0), 10, False),
(datetime(2014, 4, 20, 0, 0), 2, False),
(datetime(2014, 4, 22, 0, 0), 2, False),
(datetime(2014, 4, 25, 0, 0), 3, False),
(datetime(2014, 4, 26, 0, 0), 2, False),
(datetime(2014, 4, 27, 0, 0), 2, False),
(datetime(2014, 5, 1, 0, 0), 2, False),
(datetime(2014, 5, 2, 0, 0), 1, False),
] == r.facets.frequency
assert [
("ok", 19, False),
("good", 14, False),
("better", 19, False),
] == r.facets.deletions
async def test_term_filters_are_shown_as_selected_and_data_is_filtered(
data_client, commit_search_cls
):
cs = commit_search_cls(filters={"files": "test_opensearchpy/test_dsl"})
r = await cs.execute()
assert 35 == r.hits.total.value
assert [
("opensearchpy", 39, False),
("test_opensearchpy", 35, False),
("test_opensearchpy/test_dsl", 35, True),
("opensearchpy/query.py", 18, False),
("test_opensearchpy/test_dsl/test_search.py", 15, False),
("opensearchpy/utils.py", 14, False),
("test_opensearchpy/test_dsl/test_query.py", 13, False),
("opensearchpy/search.py", 12, False),
("opensearchpy/aggs.py", 11, False),
("test_opensearchpy/test_dsl/test_result.py", 5, False),
] == r.facets.files
assert [
(datetime(2014, 3, 3, 0, 0), 1, False),
(datetime(2014, 3, 5, 0, 0), 2, False),
(datetime(2014, 3, 6, 0, 0), 3, False),
(datetime(2014, 3, 7, 0, 0), 6, False),
(datetime(2014, 3, 10, 0, 0), 1, False),
(datetime(2014, 3, 15, 0, 0), 3, False),
(datetime(2014, 3, 21, 0, 0), 2, False),
(datetime(2014, 3, 23, 0, 0), 1, False),
(datetime(2014, 3, 24, 0, 0), 7, False),
(datetime(2014, 4, 20, 0, 0), 1, False),
(datetime(2014, 4, 25, 0, 0), 3, False),
(datetime(2014, 4, 26, 0, 0), 2, False),
(datetime(2014, 4, 27, 0, 0), 1, False),
(datetime(2014, 5, 1, 0, 0), 1, False),
(datetime(2014, 5, 2, 0, 0), 1, False),
] == r.facets.frequency
assert [
("ok", 12, False),
("good", 10, False),
("better", 13, False),
] == r.facets.deletions
async def test_range_filters_are_shown_as_selected_and_data_is_filtered(
data_client, commit_search_cls
):
cs = commit_search_cls(filters={"deletions": "better"})
r = await cs.execute()
assert 19 == r.hits.total.value
async def test_pagination(data_client, commit_search_cls):
cs = commit_search_cls()
cs = cs[0:20]
assert 52 == await cs.count()
assert 20 == len(await cs.execute())
@@ -0,0 +1,114 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
import pytest
from opensearchpy import Date, Text
from opensearchpy._async.helpers.document import AsyncDocument
from opensearchpy._async.helpers.index import AsyncIndex, AsyncIndexTemplate
from opensearchpy.helpers import analysis
pytestmark = pytest.mark.asyncio
class Post(AsyncDocument):
title = Text(analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword"))
published_from = Date()
async def test_index_template_works(write_client):
it = AsyncIndexTemplate("test-template", "test-*")
it.document(Post)
it.settings(number_of_replicas=0, number_of_shards=1)
await it.save()
i = AsyncIndex("test-blog")
await i.create()
assert {
"test-blog": {
"mappings": {
"properties": {
"title": {"type": "text", "analyzer": "my_analyzer"},
"published_from": {"type": "date"},
}
}
}
} == await write_client.indices.get_mapping(index="test-blog")
async def test_index_can_be_saved_even_with_settings(write_client):
i = AsyncIndex("test-blog", using=write_client)
i.settings(number_of_shards=3, number_of_replicas=0)
await i.save()
i.settings(number_of_replicas=1)
await i.save()
assert (
"1"
== (await i.get_settings())["test-blog"]["settings"]["index"][
"number_of_replicas"
]
)
async def test_index_exists(data_client):
assert await AsyncIndex("git").exists()
assert not await AsyncIndex("not-there").exists()
async def test_index_can_be_created_with_settings_and_mappings(write_client):
i = AsyncIndex("test-blog", using=write_client)
i.document(Post)
i.settings(number_of_replicas=0, number_of_shards=1)
await i.create()
assert {
"test-blog": {
"mappings": {
"properties": {
"title": {"type": "text", "analyzer": "my_analyzer"},
"published_from": {"type": "date"},
}
}
}
} == await write_client.indices.get_mapping(index="test-blog")
settings = await write_client.indices.get_settings(index="test-blog")
assert settings["test-blog"]["settings"]["index"]["number_of_replicas"] == "0"
assert settings["test-blog"]["settings"]["index"]["number_of_shards"] == "1"
assert settings["test-blog"]["settings"]["index"]["analysis"] == {
"analyzer": {"my_analyzer": {"type": "custom", "tokenizer": "keyword"}}
}
async def test_delete(write_client):
await write_client.indices.create(
index="test-index",
body={"settings": {"number_of_replicas": 0, "number_of_shards": 1}},
)
i = AsyncIndex("test-index", using=write_client)
await i.delete()
assert not await write_client.indices.exists(index="test-index")
async def test_multiple_indices_with_same_doc_type_work(write_client):
i1 = AsyncIndex("test-index-1", using=write_client)
i2 = AsyncIndex("test-index-2", using=write_client)
for i in i1, i2:
i.document(Post)
await i.create()
for i in ("test-index-1", "test-index-2"):
settings = await write_client.indices.get_settings(index=i)
assert settings[i]["settings"]["index"]["analysis"] == {
"analyzer": {"my_analyzer": {"type": "custom", "tokenizer": "keyword"}}
}
@@ -0,0 +1,158 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
import pytest
from pytest import raises
from opensearchpy import exceptions
from opensearchpy._async.helpers import mapping
from opensearchpy.helpers import analysis
pytestmark = pytest.mark.asyncio
async def test_mapping_saved_into_opensearch(write_client):
m = mapping.AsyncMapping()
m.field(
"name", "text", analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword")
)
m.field("tags", "keyword")
await m.save("test-mapping", using=write_client)
assert {
"test-mapping": {
"mappings": {
"properties": {
"name": {"type": "text", "analyzer": "my_analyzer"},
"tags": {"type": "keyword"},
}
}
}
} == await write_client.indices.get_mapping(index="test-mapping")
async def test_mapping_saved_into_opensearch_when_index_already_exists_closed(
write_client,
):
m = mapping.AsyncMapping()
m.field(
"name", "text", analyzer=analysis.analyzer("my_analyzer", tokenizer="keyword")
)
await write_client.indices.create(index="test-mapping")
with raises(exceptions.IllegalOperation):
await m.save("test-mapping", using=write_client)
await write_client.cluster.health(index="test-mapping", wait_for_status="yellow")
await write_client.indices.close(index="test-mapping")
await m.save("test-mapping", using=write_client)
assert {
"test-mapping": {
"mappings": {
"properties": {"name": {"type": "text", "analyzer": "my_analyzer"}}
}
}
} == await write_client.indices.get_mapping(index="test-mapping")
async def test_mapping_saved_into_opensearch_when_index_already_exists_with_analysis(
write_client,
):
m = mapping.AsyncMapping()
analyzer = analysis.analyzer("my_analyzer", tokenizer="keyword")
m.field("name", "text", analyzer=analyzer)
new_analysis = analyzer.get_analysis_definition()
new_analysis["analyzer"]["other_analyzer"] = {
"type": "custom",
"tokenizer": "whitespace",
}
await write_client.indices.create(
index="test-mapping", body={"settings": {"analysis": new_analysis}}
)
m.field("title", "text", analyzer=analyzer)
await m.save("test-mapping", using=write_client)
assert {
"test-mapping": {
"mappings": {
"properties": {
"name": {"type": "text", "analyzer": "my_analyzer"},
"title": {"type": "text", "analyzer": "my_analyzer"},
}
}
}
} == await write_client.indices.get_mapping(index="test-mapping")
async def test_mapping_gets_updated_from_opensearch(write_client):
await write_client.indices.create(
index="test-mapping",
body={
"settings": {"number_of_shards": 1, "number_of_replicas": 0},
"mappings": {
"date_detection": False,
"properties": {
"title": {
"type": "text",
"analyzer": "snowball",
"fields": {"raw": {"type": "keyword"}},
},
"created_at": {"type": "date"},
"comments": {
"type": "nested",
"properties": {
"created": {"type": "date"},
"author": {
"type": "text",
"analyzer": "snowball",
"fields": {"raw": {"type": "keyword"}},
},
},
},
},
},
},
)
m = await mapping.AsyncMapping.from_opensearch("test-mapping", using=write_client)
assert ["comments", "created_at", "title"] == list(
sorted(m.properties.properties._d_.keys())
)
assert {
"date_detection": False,
"properties": {
"comments": {
"type": "nested",
"properties": {
"created": {"type": "date"},
"author": {
"analyzer": "snowball",
"fields": {"raw": {"type": "keyword"}},
"type": "text",
},
},
},
"created_at": {"type": "date"},
"title": {
"analyzer": "snowball",
"fields": {"raw": {"type": "keyword"}},
"type": "text",
},
},
} == m.to_dict()
# test same with alias
await write_client.indices.put_alias(index="test-mapping", name="test-alias")
m2 = await mapping.AsyncMapping.from_opensearch("test-alias", using=write_client)
assert m2.to_dict() == m.to_dict()
@@ -0,0 +1,161 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
from __future__ import unicode_literals
import pytest
from pytest import raises
from opensearchpy import Date, Keyword, Q, Text, TransportError
from opensearchpy._async.helpers.document import AsyncDocument
from opensearchpy._async.helpers.search import AsyncMultiSearch, AsyncSearch
from opensearchpy.helpers.response import aggs
from test_opensearchpy.test_server.test_helpers.test_data import FLAT_DATA
pytestmark = pytest.mark.asyncio
class Repository(AsyncDocument):
created_at = Date()
description = Text(analyzer="snowball")
tags = Keyword()
@classmethod
def search(cls):
return super(Repository, cls).search().filter("term", commit_repo="repo")
class Index:
name = "git"
class Commit(AsyncDocument):
class Index:
name = "flat-git"
async def test_filters_aggregation_buckets_are_accessible(data_client):
has_tests_query = Q("term", files="test_opensearchpy/test_dsl")
s = Commit.search()[0:0]
s.aggs.bucket("top_authors", "terms", field="author.name.raw").bucket(
"has_tests", "filters", filters={"yes": has_tests_query, "no": ~has_tests_query}
).metric("lines", "stats", field="stats.lines")
response = await s.execute()
assert isinstance(
response.aggregations.top_authors.buckets[0].has_tests.buckets.yes, aggs.Bucket
)
assert (
35
== response.aggregations.top_authors.buckets[0].has_tests.buckets.yes.doc_count
)
assert (
228
== response.aggregations.top_authors.buckets[0].has_tests.buckets.yes.lines.max
)
async def test_top_hits_are_wrapped_in_response(data_client):
s = Commit.search()[0:0]
s.aggs.bucket("top_authors", "terms", field="author.name.raw").metric(
"top_commits", "top_hits", size=5
)
response = await s.execute()
top_commits = response.aggregations.top_authors.buckets[0].top_commits
assert isinstance(top_commits, aggs.TopHitsData)
assert 5 == len(top_commits)
hits = [h for h in top_commits]
assert 5 == len(hits)
assert isinstance(hits[0], Commit)
async def test_inner_hits_are_wrapped_in_response(data_client):
s = AsyncSearch(index="git")[0:1].query(
"has_parent", parent_type="repo", inner_hits={}, query=Q("match_all")
)
response = await s.execute()
commit = response.hits[0]
assert isinstance(commit.meta.inner_hits.repo, response.__class__)
assert repr(commit.meta.inner_hits.repo[0]).startswith("<Hit(git/opensearch-py): ")
async def test_scan_respects_doc_types(data_client):
result = Repository.search().scan()
repos = await get_result(result)
assert 1 == len(repos)
assert isinstance(repos[0], Repository)
assert repos[0].organization == "opensearch"
async def test_scan_iterates_through_all_docs(data_client):
s = AsyncSearch(index="flat-git")
result = s.scan()
commits = await get_result(result)
assert 52 == len(commits)
assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
async def get_result(b):
a = []
async for i in b:
a.append(i)
return a
async def test_multi_search(data_client):
s1 = Repository.search()
s2 = AsyncSearch(index="flat-git")
ms = AsyncMultiSearch()
ms = ms.add(s1).add(s2)
r1, r2 = await ms.execute()
assert 1 == len(r1)
assert isinstance(r1[0], Repository)
assert r1._search is s1
assert 52 == r2.hits.total.value
assert r2._search is s2
async def test_multi_missing(data_client):
s1 = Repository.search()
s2 = AsyncSearch(index="flat-git")
s3 = AsyncSearch(index="does_not_exist")
ms = AsyncMultiSearch()
ms = ms.add(s1).add(s2).add(s3)
with raises(TransportError):
await ms.execute()
r1, r2, r3 = await ms.execute(raise_on_error=False)
assert 1 == len(r1)
assert isinstance(r1[0], Repository)
assert r1._search is s1
assert 52 == r2.hits.total.value
assert r2._search is s2
assert r3 is None
async def test_raw_subfield_can_be_used_in_aggs(data_client):
s = AsyncSearch(index="git")[0:0]
s.aggs.bucket("authors", "terms", field="author.name.raw", size=1)
r = await s.execute()
authors = r.aggregations.authors
assert 1 == len(authors)
assert {"key": "Honza Král", "doc_count": 52} == authors[0]
@@ -0,0 +1,69 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
import pytest
from opensearchpy._async.helpers.update_by_query import AsyncUpdateByQuery
from opensearchpy.helpers.search import Q
pytestmark = pytest.mark.asyncio
async def test_update_by_query_no_script(write_client, setup_ubq_tests):
index = setup_ubq_tests
ubq = (
AsyncUpdateByQuery(using=write_client)
.index(index)
.filter(~Q("exists", field="is_public"))
)
response = await ubq.execute()
assert response.total == 52
assert response["took"] > 0
assert not response.timed_out
assert response.updated == 52
assert response.deleted == 0
assert response.took > 0
assert response.success()
async def test_update_by_query_with_script(write_client, setup_ubq_tests):
index = setup_ubq_tests
ubq = (
AsyncUpdateByQuery(using=write_client)
.index(index)
.filter(~Q("exists", field="parent_shas"))
.script(source="ctx._source.is_public = false")
)
ubq = ubq.params(conflicts="proceed")
response = await ubq.execute()
assert response.total == 2
assert response.updated == 2
assert response.version_conflicts == 0
async def test_delete_by_query_with_script(write_client, setup_ubq_tests):
index = setup_ubq_tests
ubq = (
AsyncUpdateByQuery(using=write_client)
.index(index)
.filter(Q("match", parent_shas="1dd19210b5be92b960f7db6f66ae526288edccc3"))
.script(source='ctx.op = "delete"')
)
ubq = ubq.params(conflicts="proceed")
response = await ubq.execute()
assert response.total == 1
assert response.deleted == 1
assert response.success()