diff --git a/src/mango/test/15-execution-stats-test.py b/src/mango/test/15-execution-stats-test.py deleted file mode 100644 index f812c2c5cc6..00000000000 --- a/src/mango/test/15-execution-stats-test.py +++ /dev/null @@ -1,161 +0,0 @@ -# Licensed 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. - - -import mango -import os -import unittest - - -class ExecutionStatsTests(mango.UserDocsTests): - def test_simple_json_index(self): - resp = self.db.find({"age": {"$lt": 35}}, return_raw=True, executionStats=True) - self.assertEqual(len(resp["docs"]), 3) - self.assertEqual(resp["execution_stats"]["total_keys_examined"], 3) - self.assertEqual(resp["execution_stats"]["total_docs_examined"], 3) - self.assertEqual(resp["execution_stats"]["total_quorum_docs_examined"], 0) - self.assertEqual(resp["execution_stats"]["results_returned"], 3) - # See https://github.com/apache/couchdb/issues/1732 - # Erlang os:timestamp() only has ms accuracy on Windows! - if os.name != "nt": - self.assertGreater(resp["execution_stats"]["execution_time_ms"], 0) - - def test_no_execution_stats(self): - resp = self.db.find({"age": {"$lt": 35}}, return_raw=True, executionStats=False) - assert "execution_stats" not in resp - - def test_quorum_json_index(self): - resp = self.db.find( - {"age": {"$lt": 35}}, return_raw=True, r=3, executionStats=True - ) - self.assertEqual(len(resp["docs"]), 3) - self.assertEqual(resp["execution_stats"]["total_keys_examined"], 3) - self.assertEqual(resp["execution_stats"]["total_docs_examined"], 0) - self.assertEqual(resp["execution_stats"]["total_quorum_docs_examined"], 3) - self.assertEqual(resp["execution_stats"]["results_returned"], 3) - # See https://github.com/apache/couchdb/issues/1732 - # Erlang os:timestamp() only has ms accuracy on Windows! - if os.name != "nt": - self.assertGreater(resp["execution_stats"]["execution_time_ms"], 0) - - def test_results_returned_limit(self): - resp = self.db.find( - {"age": {"$lt": 35}}, limit=2, return_raw=True, executionStats=True - ) - self.assertEqual(resp["execution_stats"]["results_returned"], len(resp["docs"])) - - def test_no_matches_index_scan(self): - resp = self.db.find( - {"age": {"$lt": 35}, "nomatch": "me"}, return_raw=True, executionStats=True - ) - self.assertEqual(resp["execution_stats"]["total_docs_examined"], 3) - self.assertEqual(resp["execution_stats"]["results_returned"], 0) - - def test_covering_json_index(self): - resp = self.db.find( - {"age": {"$lt": 35}}, - fields=["_id", "age"], - return_raw=True, - executionStats=True, - ) - self.assertEqual(len(resp["docs"]), 3) - self.assertEqual(resp["execution_stats"]["total_keys_examined"], 3) - self.assertEqual(resp["execution_stats"]["total_docs_examined"], 0) - self.assertEqual(resp["execution_stats"]["total_quorum_docs_examined"], 0) - self.assertEqual(resp["execution_stats"]["results_returned"], 3) - - def test_reporting_consistency(self): - cases = [ - { - "title": "with limit", - "selector": {"age": {"$lte": 42}}, - "fields": ["name", "email", "age"], - "limit": 3, - "total_keys_examined": 4, - "total_docs_examined": 4, - "results_returned": 3, - }, - { - "title": "partial matches", - "selector": {"favorites": {"$elemMatch": {"$eq": "Erlang"}}}, - "fields": ["name", "email", "twitter"], - "limit": 200, - "total_keys_examined": 15, - "total_docs_examined": 15, - "results_returned": 6, - }, - { - "title": "no matches, using _all_docs", - "selector": {"foo": "bar"}, - "fields": [], - "limit": 200, - "total_keys_examined": 25, - "total_docs_examined": 25, - "results_returned": 0, - }, - { - "title": "no matches, indexed column (no keys examined)", - "selector": {"name.first": "Lee", "name.last": "Jackson"}, - "fields": ["email", "twitter"], - "limit": 200, - "total_keys_examined": 0, - "total_docs_examined": 0, - "results_returned": 0, - }, - { - "title": "no matches, indexed column", - "selector": {"favorites": {"$elemMatch": {"$eq": "Haskell"}}}, - "fields": ["name", "email", "twitter"], - "limit": 200, - "total_keys_examined": 15, - "total_docs_examined": 15, - "results_returned": 0, - }, - ] - - for case in cases: - with self.subTest(scenario=case["title"]): - resp = self.db.find( - case["selector"], - fields=case["fields"], - limit=case["limit"], - return_raw=True, - executionStats=True, - ) - executionStats = resp["execution_stats"] - self.assertEqual( - executionStats["total_keys_examined"], case["total_keys_examined"] - ) - self.assertEqual( - executionStats["total_docs_examined"], case["total_docs_examined"] - ) - self.assertEqual( - executionStats["results_returned"], case["results_returned"] - ) - - -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class ExecutionStatsTests_Text(mango.UserDocsTextTests): - def test_simple_text_index(self): - resp = self.db.find( - {"$text": "Stephanie"}, return_raw=True, executionStats=True - ) - self.assertEqual(len(resp["docs"]), 1) - self.assertEqual(resp["execution_stats"]["total_keys_examined"], 1) - self.assertEqual(resp["execution_stats"]["total_docs_examined"], 1) - self.assertEqual(resp["execution_stats"]["total_quorum_docs_examined"], 0) - self.assertEqual(resp["execution_stats"]["results_returned"], 1) - self.assertGreater(resp["execution_stats"]["execution_time_ms"], 0) - - def test_no_execution_stats(self): - resp = self.db.find({"$text": "Stephanie"}, return_raw=True) - self.assertNotIn("execution_stats", resp) diff --git a/test/elixir/test/config/search.elixir b/test/elixir/test/config/search.elixir index 87715d4caf3..02d8b2d9b31 100644 --- a/test/elixir/test/config/search.elixir +++ b/test/elixir/test/config/search.elixir @@ -38,5 +38,9 @@ ], "LimitTests": [ "limit field" + ], + "ExecutionStatsTestsText": [ + "simple text index", + "no execution stats" ] } diff --git a/test/elixir/test/config/suite.elixir b/test/elixir/test/config/suite.elixir index b3fb950846c..71e558075fe 100644 --- a/test/elixir/test/config/suite.elixir +++ b/test/elixir/test/config/suite.elixir @@ -735,5 +735,18 @@ ], "IgnoreDesignDocsForAllDocsIndexTests": [ "should not return design docs" + ], + "ExecutionStatsTests": [ + "simple json index", + "no execution stats", + "quorum json index", + "results returned limit", + "no matches index scan", + "covering json index", + "scenario with limit", + "scenario partial matches", + "scenario no matches, using _all_docs", + "scenario no matches, indexed column (no keys examined)", + "scenario no matches, indexed column" ] } diff --git a/test/elixir/test/mango/15_execution_stats_test.exs b/test/elixir/test/mango/15_execution_stats_test.exs new file mode 100644 index 00000000000..e6f7ea54f95 --- /dev/null +++ b/test/elixir/test/mango/15_execution_stats_test.exs @@ -0,0 +1,199 @@ +# Licensed 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. + +defmodule ExecutionStatsTests do + use CouchTestCase + use ExUnit.Case + + @db_name "execution-stats-docs" + + setup do + UserDocs.setup(@db_name) + end + + test "simple json index" do + selector = %{"age" => %{"$lt" => 35}} + {:ok, raw} = MangoDatabase.find(@db_name, selector, return_raw: true, executionStats: true) + + assert length(raw["docs"]) == 3 + assert raw["execution_stats"]["total_keys_examined"] == 3 + assert raw["execution_stats"]["total_docs_examined"] == 3 + assert raw["execution_stats"]["total_quorum_docs_examined"] == 0 + assert raw["execution_stats"]["results_returned"] == 3 + assert raw["execution_stats"]["execution_time_ms"] > 0 + end + + test "no execution stats" do + selector = %{"age" => %{"$lt" => 35}} + {:ok, raw} = MangoDatabase.find(@db_name, selector, return_raw: true, executionStats: false) + + refute Map.has_key?(raw, "execution_stats") + end + + test "quorum json index" do + selector = %{"age" => %{"$lt" => 35}} + {:ok, raw} = MangoDatabase.find( + @db_name, + selector, + return_raw: true, + r: 3, + executionStats: true + ) + + assert length(raw["docs"]) == 3 + assert raw["execution_stats"]["total_keys_examined"] == 3 + assert raw["execution_stats"]["total_docs_examined"] == 0 + assert raw["execution_stats"]["total_quorum_docs_examined"] == 3 + assert raw["execution_stats"]["results_returned"] == 3 + assert raw["execution_stats"]["execution_time_ms"] > 0 + end + + test "results returned limit" do + selector = %{"age" => %{"$lt" => 35}} + {:ok, raw} = MangoDatabase.find( + @db_name, + selector, + return_raw: true, + limit: 2, + executionStats: true + ) + + assert raw["execution_stats"]["results_returned"] == length(raw["docs"]) + end + + test "no matches index scan" do + selector = %{"age" => %{"$lt" => 35}, "nomatch" => "me"} + {:ok, raw} = MangoDatabase.find( + @db_name, + selector, + return_raw: true, + executionStats: true + ) + + assert raw["execution_stats"]["total_docs_examined"] == 3 + assert raw["execution_stats"]["results_returned"] == 0 + end + + test "covering json index" do + selector = %{"age" => %{"$lt" => 35}} + {:ok, raw} = MangoDatabase.find( + @db_name, + selector, + fields: ["_id", "age"], + return_raw: true, + executionStats: true + ) + + assert length(raw["docs"]) == 3 + assert raw["execution_stats"]["total_keys_examined"] == 3 + assert raw["execution_stats"]["total_docs_examined"] == 0 + assert raw["execution_stats"]["total_quorum_docs_examined"] == 0 + assert raw["execution_stats"]["results_returned"] == 3 + end + + # reporting consistency + @cases [ + %{ + title: "with limit", + selector: %{"age" => %{"$lte" => 42}}, + fields: ["name", "email", "age"], + limit: 3, + total_keys_examined: 4, + total_docs_examined: 4, + results_returned: 3 + + }, + %{ + title: "partial matches", + selector: %{"favorites" => %{"$elemMatch" => %{"$eq" => "Erlang"}}}, + fields: ["name", "email", "twitter"], + limit: 200, + total_keys_examined: 15, + total_docs_examined: 15, + results_returned: 6, + }, + %{ + title: "no matches, using _all_docs", + selector: %{"foo" => "bar"}, + fields: [], + limit: 200, + total_keys_examined: 25, + total_docs_examined: 25, + results_returned: 0, + }, + %{ + title: "no matches, indexed column (no keys examined)", + selector: %{"name.first" => "Lee", "name.last" => "Jackson"}, + fields: ["email", "twitter"], + limit: 200, + total_keys_examined: 0, + total_docs_examined: 0, + results_returned: 0, + }, + %{ + title: "no matches, indexed column", + selector: %{"favorites" => %{"$elemMatch" => %{"$eq" => "Haskell"}}}, + fields: ["name", "email", "twitter"], + limit: 200, + total_keys_examined: 15, + total_docs_examined: 15, + results_returned: 0, + }] + + for case <- @cases do + test "scenario #{case.title}" do + case = unquote(Macro.escape(case)) + {:ok, resp} = MangoDatabase.find( + @db_name, + case.selector, + fields: case.fields, + limit: case.limit, + return_raw: true, + executionStats: true + ) + + execution_stats = resp["execution_stats"] + assert execution_stats["total_keys_examined"] == case.total_keys_examined + assert execution_stats["total_docs_examined"] == case.total_docs_examined + assert execution_stats["results_returned"] == case.results_returned + end + end +end + +defmodule ExecutionStatsTestsText do + use CouchTestCase + use ExUnit.Case + + @db_name "execution-stats-text-docs" + + setup do + UserDocs.setup(@db_name, "text") + end + + test "simple text index" do + selector = %{"$text" => "Stephanie"} + {:ok, raw} = MangoDatabase.find(@db_name, selector, return_raw: true, executionStats: true) + + assert length(raw["docs"]) == 1 + assert raw["execution_stats"]["total_keys_examined"] == 1 + assert raw["execution_stats"]["total_docs_examined"] == 1 + assert raw["execution_stats"]["total_quorum_docs_examined"] == 0 + assert raw["execution_stats"]["results_returned"] == 1 + assert raw["execution_stats"]["execution_time_ms"] > 0 + end + + test "no execution stats" do + selector = %{"$text" => "Stephanie"} + {:ok, raw} = MangoDatabase.find(@db_name, selector, return_raw: true) + refute Map.has_key?(raw, "execution_stats") + end +end \ No newline at end of file