diff --git a/Makefile b/Makefile index 6847037df77..06578a6ebfc 100644 --- a/Makefile +++ b/Makefile @@ -284,7 +284,7 @@ ifneq ($(_WITH_CLOUSEAU), ) "$(_WITH_CLOUSEAU)" \ "$(TEST_OPTS)" \ --locald-config test/config/test-config.ini \ - --no-eval 'mix test --trace --include test/elixir/test/config/search.elixir' + --no-eval 'mix test --trace --include test/elixir/test/config/search.elixir $(EXUNIT_OPTS)' else @echo "Warning: Clouseau is not enabled, \`elixir-search\` cannot be run." endif diff --git a/test/elixir/lib/couch.ex b/test/elixir/lib/couch.ex index efdfe31eba8..a119095a9f0 100644 --- a/test/elixir/lib/couch.ex +++ b/test/elixir/lib/couch.ex @@ -117,7 +117,7 @@ defmodule Couch do def process_request_body(body) do if is_map(body) do - :jiffy.encode(body) + :jiffy.encode(body, [:use_nil]) else body end @@ -131,7 +131,7 @@ defmodule Couch do content_type = headers[:"Content-Type"] if !!content_type and String.match?(content_type, ~r/application\/json/) do - body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps, :use_nil]) else process_response_body(body) end diff --git a/test/elixir/lib/couch/dbtest.ex b/test/elixir/lib/couch/dbtest.ex index 8a1a32449db..abc52b2a728 100644 --- a/test/elixir/lib/couch/dbtest.ex +++ b/test/elixir/lib/couch/dbtest.ex @@ -90,7 +90,7 @@ defmodule Couch.DBTest do if prev_value != "" do url = "/_node/#{node}/_config/#{section}/#{key}" headers = ["X-Couch-Persist": "false"] - body = :jiffy.encode(prev_value) + body = :jiffy.encode(prev_value, [:use_nil]) resp = Couch.put(url, headers: headers, body: body) assert resp.status_code == 200 else @@ -109,7 +109,7 @@ defmodule Couch.DBTest do Enum.map(resp.body["all_nodes"], fn node -> url = "/_node/#{node}/_config/#{section}/#{key}" headers = ["X-Couch-Persist": "false"] - body = :jiffy.encode(value) + body = :jiffy.encode(value, [:use_nil]) resp = Couch.put(url, headers: headers, body: body) assert resp.status_code == 200 {node, resp.body} @@ -494,7 +494,7 @@ defmodule Couch.DBTest do Couch.put( "/_node/#{node}/_config/#{setting.section}/#{setting.key}", headers: ["X-Couch-Persist": false], - body: :jiffy.encode(setting.value) + body: :jiffy.encode(setting.value, [:use_nil]) ) assert resp.status_code == 200 @@ -525,7 +525,7 @@ defmodule Couch.DBTest do Couch.put( "/_node/#{node}/_config/#{setting.section}/#{setting.key}", headers: ["X-Couch-Persist": false], - body: :jiffy.encode(value) + body: :jiffy.encode(value, [:use_nil]) ) assert resp.status_code == 200 diff --git a/test/elixir/lib/couch_raw.ex b/test/elixir/lib/couch_raw.ex index 62a0bbd0ed2..641612c9cd7 100644 --- a/test/elixir/lib/couch_raw.ex +++ b/test/elixir/lib/couch_raw.ex @@ -46,7 +46,7 @@ defmodule Rawresp do def process_request_body(body) do if is_map(body) do - :jiffy.encode(body) + :jiffy.encode(body, [:use_nil]) else body end diff --git a/test/elixir/test/all_docs_test.exs b/test/elixir/test/all_docs_test.exs index 3d07e12e89c..63b2ad5e460 100644 --- a/test/elixir/test/all_docs_test.exs +++ b/test/elixir/test/all_docs_test.exs @@ -116,7 +116,7 @@ defmodule AllDocsTest do assert row["key"] == "1" assert row["id"] == "1" assert row["value"]["deleted"] - assert row["doc"] == :null + assert row["doc"] == nil # Add conflicts conflicted_doc1 = %{ diff --git a/test/elixir/test/attachments_multipart_test.exs b/test/elixir/test/attachments_multipart_test.exs index 1161140a396..6a63df0e055 100644 --- a/test/elixir/test/attachments_multipart_test.exs +++ b/test/elixir/test/attachments_multipart_test.exs @@ -152,7 +152,7 @@ defmodule AttachmentMultipartTest do assert Enum.at(sections, 2).headers["Content-Disposition"] == ~s(attachment; filename="bar.txt") - doc = :jiffy.decode(Enum.at(sections, 0).body, [:return_maps]) + doc = :jiffy.decode(Enum.at(sections, 0).body, [:return_maps, :use_nil]) assert doc["_attachments"]["foo.txt"]["follows"] == true assert doc["_attachments"]["bar.txt"]["follows"] == true @@ -175,7 +175,7 @@ defmodule AttachmentMultipartTest do sections = parse_multipart(resp) assert length(sections) == 2 - doc = :jiffy.decode(Enum.at(sections, 0).body, [:return_maps]) + doc = :jiffy.decode(Enum.at(sections, 0).body, [:return_maps, :use_nil]) assert doc["_attachments"]["foo.txt"]["stub"] == true assert doc["_attachments"]["bar.txt"]["follows"] == true @@ -206,7 +206,7 @@ defmodule AttachmentMultipartTest do assert length(inner_sections) == 2 assert Enum.at(inner_sections, 0).headers["Content-Type"] == "application/json" - doc = :jiffy.decode(Enum.at(inner_sections, 0).body, [:return_maps]) + doc = :jiffy.decode(Enum.at(inner_sections, 0).body, [:return_maps, :use_nil]) assert doc["_attachments"]["foo.txt"]["stub"] == true assert doc["_attachments"]["bar.txt"]["follows"] == true @@ -228,7 +228,7 @@ defmodule AttachmentMultipartTest do assert length(sections) == 2 - doc = :jiffy.decode(Enum.at(sections, 0).body, [:return_maps]) + doc = :jiffy.decode(Enum.at(sections, 0).body, [:return_maps, :use_nil]) assert doc["_attachments"]["foo.txt"]["stub"] == true assert doc["_attachments"]["bar.txt"]["follows"] == true assert Enum.at(sections, 1).body == "this is 18 chars l" @@ -377,7 +377,7 @@ defmodule AttachmentMultipartTest do assert length(inner_sections) == 3 assert Enum.at(inner_sections, 0).headers["Content-Type"] == "application/json" - doc = :jiffy.decode(Enum.at(inner_sections, 0).body, [:return_maps]) + doc = :jiffy.decode(Enum.at(inner_sections, 0).body, [:return_maps, :use_nil]) assert doc["_attachments"]["lorem.txt"]["follows"] == true assert doc["_attachments"]["lorem.txt"]["encoding"] == "gzip" assert doc["_attachments"]["data.bin"]["follows"] == true @@ -414,7 +414,7 @@ defmodule AttachmentMultipartTest do # 2 inner sections: a document body section plus 1 attachment data section assert length(inner_sections) == 2 assert Enum.at(inner_sections, 0).headers["Content-Type"] == "application/json" - doc = :jiffy.decode(Enum.at(inner_sections, 0).body, [:return_maps]) + doc = :jiffy.decode(Enum.at(inner_sections, 0).body, [:return_maps, :use_nil]) assert doc["_attachments"]["lorem.txt"]["follows"] == true assert doc["_attachments"]["lorem.txt"]["encoding"] == "gzip" assert Enum.at(inner_sections, 1).body != lorem @@ -434,7 +434,7 @@ defmodule AttachmentMultipartTest do boundary = Enum.at(String.split(boundary_arg, "="), 1) if String.starts_with?(boundary, ~s(")) do - :jiffy.decode(boundary) + :jiffy.decode(boundary, [:use_nil]) else boundary end diff --git a/test/elixir/test/changes_async_test.exs b/test/elixir/test/changes_async_test.exs index ae8fb41b26c..75362d8a9c8 100644 --- a/test/elixir/test/changes_async_test.exs +++ b/test/elixir/test/changes_async_test.exs @@ -407,7 +407,7 @@ defmodule ChangesAsyncTest do end defp parse_chunk(msg) do - msg.chunk |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + msg.chunk |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps, :use_nil]) end defp parse_event(msg) do @@ -419,7 +419,7 @@ defmodule ChangesAsyncTest do |> Enum.map(fn p -> p |> IO.iodata_to_binary() - |> :jiffy.decode([:return_maps]) + |> :jiffy.decode([:return_maps, :use_nil]) end) end @@ -497,7 +497,7 @@ defmodule ChangesAsyncTest do body_lines |> Enum.filter(fn line -> line != "" end) |> Enum.map(fn line -> - line |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + line |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps, :use_nil]) end) end diff --git a/test/elixir/test/changes_test.exs b/test/elixir/test/changes_test.exs index 8547af59fac..9fff12e7255 100644 --- a/test/elixir/test/changes_test.exs +++ b/test/elixir/test/changes_test.exs @@ -198,7 +198,7 @@ defmodule ChangesTest do assert Enum.member?(changes_ids, "doc1") assert Enum.member?(changes_ids, "doc3") - encoded_doc_ids = doc_ids.doc_ids |> :jiffy.encode() + encoded_doc_ids = doc_ids.doc_ids |> :jiffy.encode([:use_nil]) resp = Couch.get("/#{db_name}/_changes", diff --git a/test/elixir/test/config/search.elixir b/test/elixir/test/config/search.elixir index b49b8d76275..87715d4caf3 100644 --- a/test/elixir/test/config/search.elixir +++ b/test/elixir/test/config/search.elixir @@ -32,5 +32,11 @@ "facet counts, empty", "facet ranges, empty", "facet ranges, non-empty" + ], + "ElemMatchTests": [ + "elem match non object" + ], + "LimitTests": [ + "limit field" ] } diff --git a/test/elixir/test/config/suite.elixir b/test/elixir/test/config/suite.elixir index 1d1e6059a36..452f6b6b050 100644 --- a/test/elixir/test/config/suite.elixir +++ b/test/elixir/test/config/suite.elixir @@ -728,5 +728,11 @@ "Creating-Updating/Deleting doc with overriden quorum should return 201-Created/200-OK", "Creating/Deleting DB should return 202-Acepted", "Creating/Updating/Deleting doc should return 202-Acepted" + ], + "BasicFindTest": [ + "simple find" + ], + "IgnoreDesignDocsForAllDocsIndexTests": [ + "should not return design docs" ] } diff --git a/test/elixir/test/config_test.exs b/test/elixir/test/config_test.exs index ac7ec93e313..7d741718dd2 100644 --- a/test/elixir/test/config_test.exs +++ b/test/elixir/test/config_test.exs @@ -23,7 +23,7 @@ defmodule ConfigTest do def set_config(context, section, key, val, status_assert) do url = "#{context[:config_url]}/#{section}/#{key}" headers = ["X-Couch-Persist": "false"] - resp = Couch.put(url, headers: headers, body: :jiffy.encode(val)) + resp = Couch.put(url, headers: headers, body: :jiffy.encode(val, [:use_nil])) if status_assert do assert resp.status_code == status_assert diff --git a/test/elixir/test/design_docs_test.exs b/test/elixir/test/design_docs_test.exs index 46f12e1532a..8ef744bdfb4 100644 --- a/test/elixir/test/design_docs_test.exs +++ b/test/elixir/test/design_docs_test.exs @@ -222,7 +222,7 @@ defmodule DesignDocsTest do result = resp.body |> IO.iodata_to_binary() - |> :jiffy.decode([:return_maps]) + |> :jiffy.decode([:return_maps, :use_nil]) assert result["language"] == "javascript" end diff --git a/test/elixir/test/design_options_test.exs b/test/elixir/test/design_options_test.exs index 95a938e380c..02015b55da6 100644 --- a/test/elixir/test/design_options_test.exs +++ b/test/elixir/test/design_options_test.exs @@ -50,7 +50,7 @@ defmodule DesignOptionsTest do row_with_key = resp.body["rows"] - |> Enum.filter(fn p -> p["key"] != :null end) + |> Enum.filter(fn p -> p["key"] != nil end) assert length(row_with_key) == 2 end diff --git a/test/elixir/test/erlang_views_test.exs b/test/elixir/test/erlang_views_test.exs index 3346c22748f..ceacfeb3d31 100644 --- a/test/elixir/test/erlang_views_test.exs +++ b/test/elixir/test/erlang_views_test.exs @@ -96,7 +96,7 @@ defmodule ErlangViewsTest do "erlang" ) - assert Map.get(List.first(results["rows"]), "key", :null) == :null + assert Map.get(List.first(results["rows"]), "key", nil) == nil assert List.first(results["rows"])["value"] > 0 end diff --git a/test/elixir/test/jsonp_test.exs b/test/elixir/test/jsonp_test.exs index 169f663879b..0dbb59b781d 100644 --- a/test/elixir/test/jsonp_test.exs +++ b/test/elixir/test/jsonp_test.exs @@ -107,7 +107,7 @@ defmodule JsonpTest do |> Enum.map(fn p -> p |> IO.iodata_to_binary() - |> :jiffy.decode([:return_maps]) + |> :jiffy.decode([:return_maps, :use_nil]) end) |> Enum.at(0) diff --git a/src/mango/test/11-ignore-design-docs-test.py b/test/elixir/test/mango/02_basic_find_test.exs similarity index 53% rename from src/mango/test/11-ignore-design-docs-test.py rename to test/elixir/test/mango/02_basic_find_test.exs index f31dcc5d136..b9ea42da6cf 100644 --- a/src/mango/test/11-ignore-design-docs-test.py +++ b/test/elixir/test/mango/02_basic_find_test.exs @@ -10,18 +10,19 @@ # License for the specific language governing permissions and limitations under # the License. -import mango -import unittest +defmodule BasicFindTest do + use CouchTestCase -DOCS = [ - {"_id": "_design/my-design-doc"}, - {"_id": "54af50626de419f5109c962f", "user_id": 0, "age": 10, "name": "Jimi"}, - {"_id": "54af50622071121b25402dc3", "user_id": 1, "age": 11, "name": "Eddie"}, -] + @db_name "basic-find" + setup do + UserDocs.setup(@db_name) + end -class IgnoreDesignDocsForAllDocsIndexTests(mango.DbPerClass): - def test_should_not_return_design_docs(self): - self.db.save_docs(DOCS) - docs = self.db.find({"_id": {"$gte": None}}) - assert len(docs) == 2 + test "simple find" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 35}}) + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + + assert user_ids == [9, 1, 7] + end +end diff --git a/test/elixir/test/mango/06_basic_text_test.exs b/test/elixir/test/mango/06_basic_text_test.exs new file mode 100644 index 00000000000..310cd9cdbba --- /dev/null +++ b/test/elixir/test/mango/06_basic_text_test.exs @@ -0,0 +1,33 @@ +# 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 ElemMatchTests do + use CouchTestCase + + @db_name "basic-text-elem-match" + + setup do + FriendDocs.setup(@db_name, "text") + end + + test "elem match non object" do + q = %{"bestfriends" => %{"$elemMatch" => %{"$eq" => "Wolverine", "$eq" => "Cyclops"}}} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["bestfriends"] == ["Wolverine", "Cyclops"] + + q = %{"results" => %{"$elemMatch" => %{"$gte" => 80, "$lt" => 85}}} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["results"] == [82, 85, 88] + end +end diff --git a/test/elixir/test/mango/08_text_limit_test.exs b/test/elixir/test/mango/08_text_limit_test.exs new file mode 100644 index 00000000000..07c6b01f98d --- /dev/null +++ b/test/elixir/test/mango/08_text_limit_test.exs @@ -0,0 +1,29 @@ +# 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 LimitTests do + use CouchTestCase + + @db_name "limit-docs" + + setup do + LimitDocs.setup(@db_name, "text") + end + + test "limit field" do + q = %{"$or" => [%{"user_id" => %{"$lt" => 10}}, %{"filtered_array.[]" => 1}]} + {:ok, docs} = MangoDatabase.find(@db_name, q, limit: 10) + + assert length(docs) == 8 + Enum.each(docs, fn d -> assert d["user_id"] < 10 end) + end +end diff --git a/test/elixir/test/mango/11_ignore_design_docs_test.exs b/test/elixir/test/mango/11_ignore_design_docs_test.exs new file mode 100644 index 00000000000..b6d90edcbde --- /dev/null +++ b/test/elixir/test/mango/11_ignore_design_docs_test.exs @@ -0,0 +1,33 @@ +# 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 IgnoreDesignDocsForAllDocsIndexTests do + use CouchTestCase + + @db_name "ignore-design-docs" + + setup do + MangoDatabase.recreate(@db_name) + docs = [ + %{"_id" => "_design/my-design-doc"}, + %{"_id" => "54af50626de419f5109c962f", "user_id" => 0, "age" => 10, "name" => "Jimi"}, + %{"_id" => "54af50622071121b25402dc3", "user_id" => 1, "age" => 11, "name" => "Eddie"} + ] + MangoDatabase.save_docs(@db_name, docs) + :ok + end + + test "should not return design docs" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"_id" => %{"$gte" => nil}}) + assert length(docs) == 2 + end +end diff --git a/test/elixir/test/nouveau_test.exs b/test/elixir/test/nouveau_test.exs index 18732766db8..888513fabdc 100644 --- a/test/elixir/test/nouveau_test.exs +++ b/test/elixir/test/nouveau_test.exs @@ -140,7 +140,7 @@ defmodule NouveauTest do def assert_status_code(resp, code) do assert resp.status_code == code, - "status code: #{resp.status_code}, resp body: #{:jiffy.encode(resp.body)}" + "status code: #{resp.status_code}, resp body: #{:jiffy.encode(resp.body, [:use_nil])}" end test "user-agent header is forbidden", _context do diff --git a/test/elixir/test/partition_crud_test.exs b/test/elixir/test/partition_crud_test.exs index 7e32abbdc10..dba575da3e0 100644 --- a/test/elixir/test/partition_crud_test.exs +++ b/test/elixir/test/partition_crud_test.exs @@ -154,7 +154,7 @@ defmodule PartitionCrudTest do "error" => "illegal_docid", "id" => "my-partition-post", "reason" => "Doc id must be of form partition:id", - "rev" => :null + "rev" => nil } } ], diff --git a/test/elixir/test/partition_mango_test.exs b/test/elixir/test/partition_mango_test.exs index 9e4f1e7838a..87a738e6248 100644 --- a/test/elixir/test/partition_mango_test.exs +++ b/test/elixir/test/partition_mango_test.exs @@ -478,7 +478,7 @@ defmodule PartitionMangoTest do %{:body => body} = resp assert body["index"]["name"] == "_all_docs" - assert body["mrargs"]["partition"] == :null + assert body["mrargs"]["partition"] == nil resp = Couch.post( @@ -493,7 +493,7 @@ defmodule PartitionMangoTest do %{:body => body} = resp assert body["index"]["def"] == %{"fields" => [%{"some" => "asc"}]} - assert body["mrargs"]["partition"] == :null + assert body["mrargs"]["partition"] == nil end @tag :with_partitioned_db diff --git a/test/elixir/test/replication_test.exs b/test/elixir/test/replication_test.exs index f6658deedb1..ed7cbee5f44 100644 --- a/test/elixir/test/replication_test.exs +++ b/test/elixir/test/replication_test.exs @@ -1627,7 +1627,7 @@ defmodule ReplicationTest do end def set_security(db_name, sec_props) do - resp = Couch.put("/#{db_name}/_security", body: :jiffy.encode(sec_props)) + resp = Couch.put("/#{db_name}/_security", body: :jiffy.encode(sec_props, [:use_nil])) assert HTTPotion.Response.success?(resp) assert resp.body["ok"] end diff --git a/test/elixir/test/reshard_basic_test.exs b/test/elixir/test/reshard_basic_test.exs index dcb198c4689..5fe5f764383 100644 --- a/test/elixir/test/reshard_basic_test.exs +++ b/test/elixir/test/reshard_basic_test.exs @@ -24,12 +24,12 @@ defmodule ReshardBasicTest do test "basic api querying, no jobs present" do summary = get_summary() assert summary["state"] == "running" - assert summary["state_reason"] == :null + assert summary["state_reason"] == nil assert summary["total"] == 0 assert summary["completed"] == 0 assert summary["failed"] == 0 assert summary["stopped"] == 0 - assert get_state() == %{"state" => "running", "reason" => :null} + assert get_state() == %{"state" => "running", "reason" => nil} assert get_jobs() == [] end @@ -57,11 +57,11 @@ defmodule ReshardBasicTest do end test "toggle global state" do - assert get_state() == %{"state" => "running", "reason" => :null} + assert get_state() == %{"state" => "running", "reason" => nil} put_state_stopped("xyz") assert get_state() == %{"state" => "stopped", "reason" => "xyz"} put_state_running() - assert get_state() == %{"state" => "running", "reason" => :null} + assert get_state() == %{"state" => "running", "reason" => nil} end test "split q=1 db shards on node1 (1 job)", context do diff --git a/test/elixir/test/rewrite_test.exs b/test/elixir/test/rewrite_test.exs index e23d6360909..34fe3b7f595 100644 --- a/test/elixir/test/rewrite_test.exs +++ b/test/elixir/test/rewrite_test.exs @@ -420,14 +420,14 @@ defmodule RewriteTest do ) assert resp.status_code == 200 - result = resp.body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + result = resp.body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps, :use_nil]) first_row = Enum.at(result["rows"], 0) assert Map.has_key?(first_row, "doc") # COUCHDB-2031 - path normalization versus qs params resp = Rawresp.get("/#{db_name}/_design/test/_rewrite/db/_design/test?meta=true") assert resp.status_code == 200 - result = resp.body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + result = resp.body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps, :use_nil]) assert result["_id"] == "_design/test" assert Map.has_key?(result, "_revs_info") diff --git a/test/elixir/test/support/friend_docs.ex b/test/elixir/test/support/friend_docs.ex new file mode 100644 index 00000000000..289bc999d64 --- /dev/null +++ b/test/elixir/test/support/friend_docs.ex @@ -0,0 +1,286 @@ +# 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 FriendDocs do + @moduledoc """ + Generated with http://www.json-generator.com/ + + With this pattern: + + [ + '{{repeat(15)}}', + { + _id: '{{index()}}', + name: { + first: '{{firstName()}}', + last: '{{surname()}}' + }, + friends: [ + '{{repeat(3)}}', + { + id: '{{index()}}', + name: { + first: '{{firstName()}}', + last: '{{surname()}}' + }, + type: '{{random("personal", "work")}}' + } + ] + } + ] + """ + + @docs [ + %{ + "_id" => "54a43171d37ae5e81bff5ae0", + "user_id" => 0, + "name" => %{"first" => "Ochoa", "last" => "Fox"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Sherman", "last" => "Davidson"}, + "type" => "personal", + }, + %{ + "id" => 1, + "name" => %{"first" => "Vargas", "last" => "Mendez"}, + "type" => "personal", + }, + %{"id" => 2, "name" => %{"first" => "Sheppard", "last" => "Cotton"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a43171958485dc32917c50", + "user_id" => 1, + "name" => %{"first" => "Sheppard", "last" => "Cotton"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Ochoa", "last" => "Fox"}, "type" => "work"}, + %{ + "id" => 1, + "name" => %{"first" => "Vargas", "last" => "Mendez"}, + "type" => "personal", + }, + %{"id" => 2, "name" => %{"first" => "Kendra", "last" => "Burns"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a431711cf025ba74bea899", + "user_id" => 2, + "name" => %{"first" => "Hunter", "last" => "Wells"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Estes", "last" => "Fischer"}, "type" => "work"}, + %{ + "id" => 1, + "name" => %{"first" => "Farrell", "last" => "Maddox"}, + "type" => "personal", + }, + %{"id" => 2, "name" => %{"first" => "Kendra", "last" => "Burns"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a4317151a70a9881ac28a4", + "user_id" => 3, + "name" => %{"first" => "Millicent", "last" => "Guy"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Luella", "last" => "Mendoza"}, "type" => "work"}, + %{ + "id" => 1, + "name" => %{"first" => "Melanie", "last" => "Foster"}, + "type" => "personal", + }, + %{"id" => 2, "name" => %{"first" => "Hopkins", "last" => "Scott"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a43171d946b78703a0e076", + "user_id" => 4, + "name" => %{"first" => "Elisabeth", "last" => "Brady"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Sofia", "last" => "Workman"}, "type" => "work"}, + %{"id" => 1, "name" => %{"first" => "Alisha", "last" => "Reilly"}, "type" => "work"}, + %{"id" => 2, "name" => %{"first" => "Ochoa", "last" => "Burch"}, "type" => "personal"}, + ], + }, + %{ + "_id" => "54a4317118abd7f1992464ee", + "user_id" => 5, + "name" => %{"first" => "Pollard", "last" => "French"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Hollie", "last" => "Juarez"}, + "type" => "personal", + }, + %{"id" => 1, "name" => %{"first" => "Nelda", "last" => "Newton"}, "type" => "personal"}, + %{"id" => 2, "name" => %{"first" => "Yang", "last" => "Pace"}, "type" => "personal"}, + ], + }, + %{ + "_id" => "54a43171f139e63d6579121e", + "user_id" => 6, + "name" => %{"first" => "Acevedo", "last" => "Morales"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Payne", "last" => "Berry"}, "type" => "personal"}, + %{ + "id" => 1, + "name" => %{"first" => "Rene", "last" => "Valenzuela"}, + "type" => "personal", + }, + %{"id" => 2, "name" => %{"first" => "Dora", "last" => "Gallegos"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a431719783cef80876dde8", + "user_id" => 7, + "name" => %{"first" => "Cervantes", "last" => "Marquez"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Maxwell", "last" => "Norman"}, + "type" => "personal", + }, + %{"id" => 1, "name" => %{"first" => "Shields", "last" => "Bass"}, "type" => "personal"}, + %{"id" => 2, "name" => %{"first" => "Luz", "last" => "Jacobson"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a43171ecc7540d1f7aceae", + "user_id" => 8, + "name" => %{"first" => "West", "last" => "Morrow"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Townsend", "last" => "Dixon"}, + "type" => "personal", + }, + %{ + "id" => 1, + "name" => %{"first" => "Callahan", "last" => "Buck"}, + "type" => "personal", + }, + %{ + "id" => 2, + "name" => %{"first" => "Rachel", "last" => "Fletcher"}, + "type" => "personal", + }, + ], + }, + %{ + "_id" => "54a4317113e831f4af041a0a", + "user_id" => 9, + "name" => %{"first" => "Cotton", "last" => "House"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Mckenzie", "last" => "Medina"}, + "type" => "personal", + }, + %{"id" => 1, "name" => %{"first" => "Cecilia", "last" => "Miles"}, "type" => "work"}, + %{"id" => 2, "name" => %{"first" => "Guerra", "last" => "Cervantes"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a43171686eb1f48ebcbe01", + "user_id" => 10, + "name" => %{"first" => "Wright", "last" => "Rivas"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Campos", "last" => "Freeman"}, + "type" => "personal", + }, + %{ + "id" => 1, + "name" => %{"first" => "Christian", "last" => "Ferguson"}, + "type" => "personal", + }, + %{"id" => 2, "name" => %{"first" => "Doreen", "last" => "Wilder"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a43171a4f3d5638c162f4f", + "user_id" => 11, + "name" => %{"first" => "Lorene", "last" => "Dorsey"}, + "friends" => [ + %{ + "id" => 0, + "name" => %{"first" => "Gibbs", "last" => "Mccarty"}, + "type" => "personal", + }, + %{"id" => 1, "name" => %{"first" => "Neal", "last" => "Franklin"}, "type" => "work"}, + %{"id" => 2, "name" => %{"first" => "Kristy", "last" => "Head"}, "type" => "personal"}, + ], + "bestfriends" => ["Wolverine", "Cyclops"], + }, + %{ + "_id" => "54a431719faa420a5b4fbeb0", + "user_id" => 12, + "name" => %{"first" => "Juanita", "last" => "Cook"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Wilkins", "last" => "Chang"}, "type" => "work"}, + %{"id" => 1, "name" => %{"first" => "Haney", "last" => "Rivera"}, "type" => "work"}, + %{"id" => 2, "name" => %{"first" => "Lauren", "last" => "Manning"}, "type" => "work"}, + ], + }, + %{ + "_id" => "54a43171e65d35f9ee8c53c0", + "user_id" => 13, + "name" => %{"first" => "Levy", "last" => "Osborn"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Vinson", "last" => "Vargas"}, "type" => "work"}, + %{"id" => 1, "name" => %{"first" => "Felicia", "last" => "Beach"}, "type" => "work"}, + %{"id" => 2, "name" => %{"first" => "Nadine", "last" => "Kemp"}, "type" => "work"}, + ], + "results" => [82, 85, 88], + }, + %{ + "_id" => "54a4317132f2c81561833259", + "user_id" => 14, + "name" => %{"first" => "Christina", "last" => "Raymond"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Herrera", "last" => "Walton"}, "type" => "work"}, + %{"id" => 1, "name" => %{"first" => "Hahn", "last" => "Rutledge"}, "type" => "work"}, + %{"id" => 2, "name" => %{"first" => "Stacie", "last" => "Harding"}, "type" => "work"}, + ], + }, + %{ + "_id" => "589f32af493145f890e1b051", + "user_id" => 15, + "name" => %{"first" => "Tanisha", "last" => "Bowers"}, + "friends" => [ + %{"id" => 0, "name" => %{"first" => "Ochoa", "last" => "Pratt"}, "type" => "personal"}, + %{"id" => 1, "name" => %{"first" => "Ochoa", "last" => "Romero"}, "type" => "personal"}, + %{"id" => 2, "name" => %{"first" => "Ochoa", "last" => "Bowman"}, "type" => "work"}, + ], + }, + ] + + def setup(db, index_type \\ "view") do + MangoDatabase.recreate(db) + MangoDatabase.save_docs(db, @docs) + + case index_type do + "view" -> add_view_indexes(db) + "text" -> add_text_indexes(db) + end + + :ok + end + + defp add_view_indexes(db) do + # TODO: this function is not defined in the Python version of this module? + end + + defp add_text_indexes(db) do + MangoDatabase.create_text_index(db) + end +end diff --git a/test/elixir/test/support/limit_docs.ex b/test/elixir/test/support/limit_docs.ex new file mode 100644 index 00000000000..5a474f2dd34 --- /dev/null +++ b/test/elixir/test/support/limit_docs.ex @@ -0,0 +1,112 @@ +# 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 LimitDocs do + @moduledoc false + @docs [ + %{"_id" => "54af50626de419f5109c962f", "user_id" => 0, "age" => 10}, + %{"_id" => "54af50622071121b25402dc3", "user_id" => 1, "age" => 11}, + %{"_id" => "54af50623809e19159a3cdd0", "user_id" => 2, "age" => 12}, + %{"_id" => "54af50629f45a0f49a441d01", "user_id" => 3, "age" => 13}, + %{"_id" => "54af50620f1755c22359a362", "user_id" => 4, "age" => 14}, + %{"_id" => "54af5062dd6f6c689ad2ca23", "user_id" => 5, "age" => 15}, + %{"_id" => "54af50623e89b432be1187b8", "user_id" => 6, "age" => 16}, + %{"_id" => "54af5062932a00270a3b5ab0", "user_id" => 7, "age" => 17}, + %{"_id" => "54af5062df773d69174e3345", "filtered_array" => [1, 2, 3], "age" => 18}, + %{"_id" => "54af50629c1153b9e21e346d", "filtered_array" => [1, 2, 3], "age" => 19}, + %{"_id" => "54af5062dabb7cc4b60e0c95", "user_id" => 10, "age" => 20}, + %{"_id" => "54af5062204996970a4439a2", "user_id" => 11, "age" => 21}, + %{"_id" => "54af50629cea39e8ea52bfac", "user_id" => 12, "age" => 22}, + %{"_id" => "54af50620597c094f75db2a1", "user_id" => 13, "age" => 23}, + %{"_id" => "54af50628d4048de0010723c", "user_id" => 14, "age" => 24}, + %{"_id" => "54af5062f339b6f44f52faf6", "user_id" => 15, "age" => 25}, + %{"_id" => "54af5062a893f17ea4402031", "user_id" => 16, "age" => 26}, + %{"_id" => "54af5062323dbc7077deb60a", "user_id" => 17, "age" => 27}, + %{"_id" => "54af506224db85bd7fcd0243", "filtered_array" => [1, 2, 3], "age" => 28}, + %{"_id" => "54af506255bb551c9cc251bf", "filtered_array" => [1, 2, 3], "age" => 29}, + %{"_id" => "54af50625a97394e07d718a1", "filtered_array" => [1, 2, 3], "age" => 30}, + %{"_id" => "54af506223f51d586b4ef529", "user_id" => 21, "age" => 31}, + %{"_id" => "54af50622740dede7d6117b7", "user_id" => 22, "age" => 32}, + %{"_id" => "54af50624efc87684a52e8fb", "user_id" => 23, "age" => 33}, + %{"_id" => "54af5062f40932760347799c", "user_id" => 24, "age" => 34}, + %{"_id" => "54af5062d9f7361951ac645d", "user_id" => 25, "age" => 35}, + %{"_id" => "54af5062f89aef302b37c3bc", "filtered_array" => [1, 2, 3], "age" => 36}, + %{"_id" => "54af5062498ec905dcb351f8", "filtered_array" => [1, 2, 3], "age" => 37}, + %{"_id" => "54af5062b1d2f2c5a85bdd7e", "user_id" => 28, "age" => 38}, + %{"_id" => "54af50625061029c0dd942b5", "filtered_array" => [1, 2, 3], "age" => 39}, + %{"_id" => "54af50628b0d08a1d23c030a", "user_id" => 30, "age" => 40}, + %{"_id" => "54af506271b6e3119eb31d46", "filtered_array" => [1, 2, 3], "age" => 41}, + %{"_id" => "54af5062b69f46424dfcf3e5", "user_id" => 32, "age" => 42}, + %{"_id" => "54af5062ed00c7dbe4d1bdcf", "user_id" => 33, "age" => 43}, + %{"_id" => "54af5062fb64e45180c9a90d", "user_id" => 34, "age" => 44}, + %{"_id" => "54af5062241c72b067127b09", "user_id" => 35, "age" => 45}, + %{"_id" => "54af50626a467d8b781a6d06", "user_id" => 36, "age" => 46}, + %{"_id" => "54af50620e992d60af03bf86", "filtered_array" => [1, 2, 3], "age" => 47}, + %{"_id" => "54af506254f992aa3c51532f", "user_id" => 38, "age" => 48}, + %{"_id" => "54af5062e99b20f301de39b9", "user_id" => 39, "age" => 49}, + %{"_id" => "54af50624fbade6b11505b5d", "user_id" => 40, "age" => 50}, + %{"_id" => "54af506278ad79b21e807ae4", "user_id" => 41, "age" => 51}, + %{"_id" => "54af5062fc7a1dcb33f31d08", "user_id" => 42, "age" => 52}, + %{"_id" => "54af5062ea2c954c650009cf", "user_id" => 43, "age" => 53}, + %{"_id" => "54af506213576c2f09858266", "user_id" => 44, "age" => 54}, + %{"_id" => "54af50624a05ac34c994b1c0", "user_id" => 45, "age" => 55}, + %{"_id" => "54af50625a624983edf2087e", "user_id" => 46, "age" => 56}, + %{"_id" => "54af50623de488c49d064355", "user_id" => 47, "age" => 57}, + %{"_id" => "54af5062628b5df08661a9d5", "user_id" => 48, "age" => 58}, + %{"_id" => "54af50620c706fc23032ae62", "user_id" => 49, "age" => 59}, + %{"_id" => "54af5062509f1e2371fe1da4", "user_id" => 50, "age" => 60}, + %{"_id" => "54af50625e96b22436791653", "user_id" => 51, "age" => 61}, + %{"_id" => "54af5062a9cb71463bb9577f", "user_id" => 52, "age" => 62}, + %{"_id" => "54af50624fea77a4221a4baf", "user_id" => 53, "age" => 63}, + %{"_id" => "54af5062c63df0a147d2417e", "user_id" => 54, "age" => 64}, + %{"_id" => "54af50623c56d78029316c9f", "user_id" => 55, "age" => 65}, + %{"_id" => "54af5062167f6e13aa0dd014", "user_id" => 56, "age" => 66}, + %{"_id" => "54af50621558abe77797d137", "filtered_array" => [1, 2, 3], "age" => 67}, + %{"_id" => "54af50624d5b36aa7cb5fa77", "user_id" => 58, "age" => 68}, + %{"_id" => "54af50620d79118184ae66bd", "user_id" => 59, "age" => 69}, + %{"_id" => "54af5062d18aafa5c4ca4935", "user_id" => 60, "age" => 71}, + %{"_id" => "54af5062fd22a409649962f4", "filtered_array" => [1, 2, 3], "age" => 72}, + %{"_id" => "54af5062e31045a1908e89f9", "user_id" => 62, "age" => 73}, + %{"_id" => "54af50624c062fcb4c59398b", "user_id" => 63, "age" => 74}, + %{"_id" => "54af506241ec83430a15957f", "user_id" => 64, "age" => 75}, + %{"_id" => "54af506224d0f888ae411101", "user_id" => 65, "age" => 76}, + %{"_id" => "54af506272a971c6cf3ab6b8", "user_id" => 66, "age" => 77}, + %{"_id" => "54af506221e25b485c95355b", "user_id" => 67, "age" => 78}, + %{"_id" => "54af5062800f7f2ca73e9623", "user_id" => 68, "age" => 79}, + %{"_id" => "54af5062bc962da30740534a", "user_id" => 69, "age" => 80}, + %{"_id" => "54af50625102d6e210fc2efd", "filtered_array" => [1, 2, 3], "age" => 81}, + %{"_id" => "54af5062e014b9d039f02c5e", "user_id" => 71, "age" => 82}, + %{"_id" => "54af5062fbd5e801dd217515", "user_id" => 72, "age" => 83}, + %{"_id" => "54af50629971992b658fcb88", "user_id" => 73, "age" => 84}, + %{"_id" => "54af5062607d53416c30bafd", "filtered_array" => [1, 2, 3], "age" => 85}, + ] + + def setup(db, index_type \\ "view") do + MangoDatabase.recreate(db) + MangoDatabase.save_docs(db, @docs) + + case index_type do + "view" -> add_view_indexes(db) + "text" -> add_text_indexes(db) + end + + :ok + end + + defp add_view_indexes(db) do + # TODO: this function is not defined in the Python version of this module? + end + + defp add_text_indexes(db) do + MangoDatabase.create_text_index(db) + end +end diff --git a/test/elixir/test/support/mango_database.ex b/test/elixir/test/support/mango_database.ex new file mode 100644 index 00000000000..1b5b4ab63a8 --- /dev/null +++ b/test/elixir/test/support/mango_database.ex @@ -0,0 +1,198 @@ +# 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 MangoDatabase do + @moduledoc false + def has_text_service() do + resp = Couch.get("/") + "search" in resp.body["features"] + end + + def recreate(db, opts \\ []) do + resp = Couch.get("/#{db}") + if resp.status_code == 200 do + docs = resp.body["doc_count"] + resp.body["doc_del_count"] + if docs > 0 do + delete(db) + create(db, opts) + end + else + create(db, opts) + end + end + + def create(db, opts \\ []) do + partitioned = Keyword.get(opts, :partitioned, false) + Couch.put("/#{db}?partitioned=#{partitioned}") + end + + defp delete(db) do + Couch.delete("/#{db}") + end + + def save_doc(db, doc, opts \\ []) do + MangoDatabase.save_docs(db, [doc], opts) + end + + def save_docs_with_conflicts(db, docs) do + body = %{"docs" => docs, "new_edits" => false} + Couch.post("/#{db}/_bulk_docs", body: body) + end + + # If a certain keyword like sort or field is passed in the options, + # then it is added to the request body. + defp put_if_set(map, key, opts, opts_key) do + if Keyword.has_key?(opts, opts_key) do + Map.put(map, key, opts[opts_key]) + else + map + end + end + + # TODO: make this use batches if necessary + def save_docs(db, docs, opts \\ []) do + query = %{} + |> put_if_set("w", opts, :w) + + result = Couch.post("/#{db}/_bulk_docs", body: %{"docs" => docs}, query: query) + zipped_docs = Enum.zip(docs, result.body) + + # This returns the doc list including _id and _rev values + resp = Enum.map(zipped_docs, fn {doc, result} -> + doc + |> Map.put("_id", result["id"]) + |> Map.put("_rev", result["rev"]) + end) + + # _bulk_docs sometimes returns errors in the body and this is captured here + errors = Enum.filter(result.body, fn r -> + Map.has_key?(r, "error") + end) + if errors == [] do + resp + else + {:error, errors} + end + end + + def create_index(db, fields, options \\ []) do + index = %{ + "fields" => fields, + } + |> put_if_set("selector", options, :selector) + |> put_if_set("partial_filter_selector", options, :partial_filter_selector) + + body = %{ + "index" => index, + "type" => "json", + "w" => 3 + } + |> put_if_set("type", options, :idx_type) + |> put_if_set("name", options, :name) + |> put_if_set("ddoc", options, :ddoc) + + resp = Couch.post("/#{db}/_index", body: body) + if resp.status_code == 200 do + {:ok, resp.body["result"] == "created"} + else + {:error, resp} + end + end + + def create_text_index(db, options \\ []) do + index = %{} + |> put_if_set("default_analyzer", options, :analyzer) + |> put_if_set("default_field", options, :default_field) + |> put_if_set("index_array_lengths", options, :index_array_lengths) + |> put_if_set("selector", options, :selector) + |> put_if_set("partial_filter_selector", options, :partial_filter_selector) + |> put_if_set("fields", options, :fields) + + body = %{ + "index" => index, + "type" => Keyword.get(options, :idx_type, "text"), + "w" => 3 + } + |> put_if_set("name", options, :name) + |> put_if_set("ddoc", options, :ddoc) + + resp = Couch.post("/#{db}/_index", body: body) + + if resp.status_code == 200 do + {:ok, resp.body["result"] == "created"} + else + {:error, resp} + end + end + + def list_indexes(db, opts \\ []) do + limit = Keyword.get(opts, :limit) + skip = Keyword.get(opts, :skip) + query = + [limit: limit, skip: skip] + |> Enum.filter(fn {_k, v} -> not is_nil(v) end) + |> Enum.map_join("&", fn {k, v} -> "#{k}=#{v}" end) + + path = + if query == "" do + "/#{db}/_index" + else + "/#{db}/_index?#{query}" + end + resp = Couch.get(path) + + if resp.status_code == 200 do + {:ok, resp.body["indexes"]} + else + {:error, resp} + end + end + + def find(db, selector, opts \\ []) do + defaults = [ + use_index: nil, + skip: 0, + limit: 25, + r: 1, + conflicts: false, + explain: false, + return_raw: false + ] + options = Keyword.merge(defaults, opts) + + path = + case options[:explain] do + true -> "/#{db}/_explain" + _ -> "/#{db}/_find" + end + + resp = Couch.post(path, body: %{ + "selector" => selector, + "use_index" => options[:use_index], + "skip" => options[:skip], + "limit" => options[:limit], + "r" => options[:r], + "conflicts" => options[:conflicts] + } + |> put_if_set("sort", options, :sort) + |> put_if_set("fields", options, :fields) + |> put_if_set("execution_stats", options, :executionStats) + |> put_if_set("allow_fallback", options, :allow_fallback) + ) + + case {(options[:explain] or options[:return_raw]), resp.status_code} do + {false, 200} -> {:ok, resp.body["docs"]} + {true, 200} -> {:ok, resp.body} + _ -> {:error, resp} + end + end +end diff --git a/test/elixir/test/support/user_docs.ex b/test/elixir/test/support/user_docs.ex new file mode 100644 index 00000000000..eb015cc64b5 --- /dev/null +++ b/test/elixir/test/support/user_docs.ex @@ -0,0 +1,401 @@ +# 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 UserDocs do + @moduledoc """ + Generated with http://www.json-generator.com/ + + With this pattern: + + [ + '{{repeat(20)}}', + { + _id: '{{guid()}}', + user_id: "{{index()}}", + name: { + first: "{{firstName()}}", + last: "{{surname()}}" + }, + age: "{{integer(18,90)}}", + location: { + state: "{{state()}}", + city: "{{city()}}", + address: { + street: "{{street()}}", + number: "{{integer(10, 10000)}}" + } + }, + company: "{{company()}}", + email: "{{email()}}", + manager: "{{bool()}}", + twitter: function(tags) { + if(this.manager) + return; + return "@" + this.email.split("@")[0]; + }, + favorites: [ + "{{repeat(2,5)}}", + "{{random('C', 'C++', 'Python', 'Ruby', 'Erlang', 'Lisp')}}" + ] + } + ] + """ + + @partitions 3 + + @docs [ + %{ + "_id" => "71562648-6acb-42bc-a182-df6b1f005b09", + "user_id" => 0, + "name" => %{"first" => "Stephanie", "last" => "Kirkland"}, + "age" => 48, + "location" => %{ + "state" => "Nevada", + "city" => "Ronco", + "address" => %{"street" => "Evergreen Avenue", "number" => 347}, + }, + "company" => "Dreamia", + "email" => "stephaniekirkland@dreamia.com", + "manager" => false, + "twitter" => "@stephaniekirkland", + "favorites" => ["Ruby", "C", "Python"], + "test" => [%{"a" => 1}, %{"b" => 2}], + }, + %{ + "_id" => "12a2800c-4fe2-45a8-8d78-c084f4e242a9", + "user_id" => 1, + "name" => %{"first" => "Abbott", "last" => "Watson"}, + "age" => 31, + "location" => %{ + "state" => "Connecticut", + "city" => "Gerber", + "address" => %{"street" => "Huntington Street", "number" => 8987}, + }, + "company" => "Talkola", + "email" => "abbottwatson@talkola.com", + "manager" => false, + "twitter" => "@abbottwatson", + "favorites" => ["Ruby", "Python", "C", %{"Versions" => %{"Alpha" => "Beta"}}], + "test" => [%{"a" => 1, "b" => 2}], + }, + %{ + "_id" => "48ca0455-8bd0-473f-9ae2-459e42e3edd1", + "user_id" => 2, + "name" => %{"first" => "Shelly", "last" => "Ewing"}, + "age" => 42, + "location" => %{ + "state" => "New Mexico", + "city" => "Thornport", + "address" => %{"street" => "Miller Avenue", "number" => 7100}, + }, + "company" => "Zialactic", + "email" => "shellyewing@zialactic.com", + "manager" => true, + "favorites" => ["Lisp", "Python", "Erlang"], + "test_in" => %{"val1" => 1, "val2" => "val2"}, + }, + %{ + "_id" => "0461444c-e60a-457d-a4bb-b8d811853f21", + "user_id" => 3, + "name" => %{"first" => "Madelyn", "last" => "Soto"}, + "age" => 79, + "location" => %{ + "state" => "Utah", + "city" => "Albany", + "address" => %{"street" => "Stockholm Street", "number" => 710}, + }, + "company" => "Tasmania", + "email" => "madelynsoto@tasmania.com", + "manager" => true, + "favorites" => [["Lisp", "Erlang", "Python"], "Erlang", "C", "Erlang"], + "11111" => "number_field", + "22222" => %{"33333" => "nested_number_field"}, + }, + %{ + "_id" => "8e1c90c0-ac18-4832-8081-40d14325bde0", + "user_id" => 4, + "name" => %{"first" => "Nona", "last" => "Horton"}, + "age" => 61, + "location" => %{ + "state" => "Georgia", + "city" => "Corinne", + "address" => %{"street" => "Woodhull Street", "number" => 6845}, + }, + "company" => "Signidyne", + "email" => "nonahorton@signidyne.com", + "manager" => false, + "twitter" => "@nonahorton", + "favorites" => ["Lisp", "C", "Ruby", "Ruby"], + "name.first" => "name dot first", + }, + %{ + "_id" => "a33d5457-741a-4dce-a217-3eab28b24e3e", + "user_id" => 5, + "name" => %{"first" => "Sheri", "last" => "Perkins"}, + "age" => 73, + "location" => %{ + "state" => "Michigan", + "city" => "Nutrioso", + "address" => %{"street" => "Bassett Avenue", "number" => 5648}, + }, + "company" => "Myopium", + "email" => "sheriperkins@myopium.com", + "manager" => true, + "favorites" => ["Lisp", "Lisp"], + }, + %{ + "_id" => "b31dad3f-ae8b-4f86-8327-dfe8770beb27", + "user_id" => 6, + "name" => %{"first" => "Tate", "last" => "Guy"}, + "age" => 47, + "location" => %{ + "state" => "Illinois", + "city" => "Helen", + "address" => %{"street" => "Schenck Court", "number" => 7392}, + }, + "company" => "Prosely", + "email" => "tateguy@prosely.com", + "manager" => true, + "favorites" => ["C", "Lisp", "Ruby", "C"], + }, + %{ + "_id" => "659d0430-b1f4-413a-a6b7-9ea1ef071325", + "user_id" => 7, + "name" => %{"first" => "Jewell", "last" => "Stafford"}, + "age" => 33, + "location" => %{ + "state" => "Iowa", + "city" => "Longbranch", + "address" => %{"street" => "Dodworth Street", "number" => 3949}, + }, + "company" => "Niquent", + "email" => "jewellstafford@niquent.com", + "manager" => true, + "favorites" => ["C", "C", "Ruby", "Ruby", "Erlang"], + "exists_field" => "should_exist1", + "ordered" => nil, + }, + %{ + "_id" => "6c0afcf1-e57e-421d-a03d-0c0717ebf843", + "user_id" => 8, + "name" => %{"first" => "James", "last" => "Mcdaniel"}, + "age" => 68, + "location" => %{ + "state" => "Maine", + "city" => "Craig", + "address" => %{"street" => "Greene Avenue", "number" => 8776}, + }, + "company" => "Globoil", + "email" => "jamesmcdaniel@globoil.com", + "manager" => true, + "favorites" => nil, + "exists_field" => "should_exist2", + "ordered" => false, + }, + %{ + "_id" => "954272af-d5ed-4039-a5eb-8ed57e9def01", + "user_id" => 9, + "name" => %{"first" => "Ramona", "last" => "Floyd"}, + "age" => 22, + "location" => %{ + "state" => "Missouri", + "city" => "Foxworth", + "address" => %{"street" => "Lott Place", "number" => 1697}, + }, + "company" => "Manglo", + "email" => "ramonafloyd@manglo.com", + "manager" => true, + "twitter" => nil, + "favorites" => ["Lisp", "Erlang", "Python"], + "exists_array" => ["should", "exist", "array1"], + "complex_field_value" => '+-()%{}[]^~&&*||"\\/? =>!', + "ordered" => true, + }, + %{ + "_id" => "e900001d-bc48-48a6-9b1a-ac9a1f5d1a03", + "user_id" => 10, + "name" => %{"first" => "Charmaine", "last" => "Mills"}, + "age" => 43, + "location" => %{ + "state" => "New Hampshire", + "city" => "Kiskimere", + "address" => %{"street" => "Nostrand Avenue", "number" => 4503}, + }, + "company" => "Lyria", + "email" => "charmainemills@lyria.com", + "manager" => true, + "favorites" => ["Erlang", "Erlang"], + "exists_array" => ["should", "exist", "array2"], + "ordered" => 9, + }, + %{ + "_id" => "b06aadcf-cd0f-4ca6-9f7e-2c993e48d4c4", + "user_id" => 11, + "name" => %{"first" => "Mathis", "last" => "Hernandez"}, + "age" => 75, + "location" => %{ + "state" => "Hawaii", + "city" => "Dupuyer", + "address" => %{"street" => "Bancroft Place", "number" => 2741}, + }, + "company" => "Affluex", + "email" => "mathishernandez@affluex.com", + "manager" => true, + "favorites" => ["Ruby", "Lisp", "C", "C++", "C++"], + "exists_object" => %{"should" => "object"}, + "ordered" => 10_000, + }, + %{ + "_id" => "5b61abc1-a3d3-4092-b9d7-ced90e675536", + "user_id" => 12, + "name" => %{"first" => "Patti", "last" => "Rosales"}, + "age" => 71, + "location" => %{ + "state" => "Pennsylvania", + "city" => "Juntura", + "address" => %{"street" => "Hunterfly Place", "number" => 7683}, + }, + "company" => "Oulu", + "email" => "pattirosales@oulu.com", + "manager" => true, + "favorites" => ["C", "Python", "Lisp"], + "exists_object" => %{"another" => "object"}, + "ordered" => "a", + }, + %{ + "_id" => "b1e70402-8add-4068-af8f-b4f3d0feb049", + "user_id" => 13, + "name" => %{"first" => "Whitley", "last" => "Harvey"}, + "age" => 78, + "location" => %{ + "state" => "Minnesota", + "city" => "Trail", + "address" => %{"street" => "Pleasant Place", "number" => 8766}, + }, + "company" => nil, + "email" => "whitleyharvey@fangold.com", + "manager" => false, + "twitter" => "@whitleyharvey", + "favorites" => ["C", "Ruby", "Ruby"], + "ordered" => "A", + }, + %{ + "_id" => "c78c529f-0b07-4947-90a6-d6b7ca81da62", + "user_id" => 14, + "name" => %{"first" => "Faith", "last" => "Hess"}, + "age" => 51, + "location" => %{ + "state" => "North Dakota", + "city" => "Axis", + "address" => %{"street" => "Brightwater Avenue", "number" => 1106}, + }, + "foo" => "bar car apple", + "company" => "Pharmex", + "email" => "faithhess@pharmex.com", + "favorites" => ["Erlang", "Python", "Lisp"], + "ordered" => "aa", + } + ] + + @users_docs [ + %{ + "_id" => "org.couchdb.user =>demo01", + "name" => "demo01", + "username" => "demo01", + "password" => "apple01", + "roles" => ["design"], + "order" => 1, + "type" => "user", + }, + %{ + "_id" => "org.couchdb.user =>demo02", + "name" => "demo02", + "username" => "demo02", + "password" => "apple02", + "roles" => ["reader"], + "order" => 2, + "type" => "user", + }, + %{ + "_id" => "org.couchdb.user =>demo03", + "name" => "demo03", + "username" => "demo03", + "password" => "apple03", + "roles" => ["reader", "writer"], + "order" => 3, + "type" => "user", + } + ] + + def setup_users(db) do + MangoDatabase.recreate(db) + MangoDatabase.save_docs(db, @users_docs) + end + + def setup(db, index_type \\ "view", partitioned \\ false) do + MangoDatabase.recreate(db, [partitioned: partitioned]) + docs = @docs + + if partitioned do + partition_docs = Enum.map(Enum.with_index(docs), fn {doc, index} -> + partition = rem(index, @partitions) + %{doc | "_id" => "#{partition}:#{doc["_id"]}"} + end) + MangoDatabase.save_docs(db, partition_docs) + else + MangoDatabase.save_docs(db, docs) + end + + case index_type do + "view" -> add_view_indexes(db) + "text" -> add_text_indexes(db) + "special" -> :ok + end + + :ok + end + + def len() do + length(@docs) + end + + defp add_view_indexes(db) do + indexes = [ + {["user_id"], "user_id"}, + {["name.last", "name.first"], "name"}, + {["age"], "age"}, + { + [ + "location.state", + "location.city", + "location.address.street", + "location.address.number", + ], + "location", + }, + {["company", "manager"], "company_and_manager"}, + {["manager"], "manager"}, + {["favorites"], "favorites"}, + {["favorites.3"], "favorites_3"}, + {["twitter"], "twitter"}, + {["ordered"], "ordered"}, + ] + + Enum.each(indexes, fn {idx, name} -> + MangoDatabase.create_index(db, idx, name: name, ddoc: name) + end) + end + + defp add_text_indexes(db) do + MangoDatabase.create_text_index(db) + end +end diff --git a/test/elixir/test/users_db_test.exs b/test/elixir/test/users_db_test.exs index bc09df9ba6c..2239eb4c247 100644 --- a/test/elixir/test/users_db_test.exs +++ b/test/elixir/test/users_db_test.exs @@ -126,7 +126,7 @@ defmodule UsersDbTest do headers: [authorization: "Basic Xzpf"] ) - assert resp.body["userCtx"]["name"] == :null + assert resp.body["userCtx"]["name"] == nil assert not Enum.member?(resp.body["info"], "authenticated") # ok, now create a conflicting edit on the jchris doc, and make sure there's no login. diff --git a/test/elixir/test/view_collation_raw_test.exs b/test/elixir/test/view_collation_raw_test.exs index ee272d72e8a..90f736621ba 100644 --- a/test/elixir/test/view_collation_raw_test.exs +++ b/test/elixir/test/view_collation_raw_test.exs @@ -13,7 +13,7 @@ defmodule ViewCollationRawTest do 3, 4, false, - :null, + nil, true, # Then objects, compared each key value in the list until different. @@ -109,7 +109,7 @@ defmodule ViewCollationRawTest do test "key query option", context do Enum.each(@values, fn value -> retry_until(fn -> - resp = Couch.get(url(context), query: %{:key => :jiffy.encode(value)}) + resp = Couch.get(url(context), query: %{:key => :jiffy.encode(value, [:use_nil])}) assert length(resp.body["rows"]) == 1 assert Enum.at(resp.body["rows"], 0)["key"] == convert(value) end) @@ -154,6 +154,6 @@ defmodule ViewCollationRawTest do end def convert(value) do - :jiffy.decode(:jiffy.encode(value), [:return_maps]) + :jiffy.decode(:jiffy.encode(value, [:use_nil]), [:return_maps, :use_nil]) end end diff --git a/test/elixir/test/view_collation_test.exs b/test/elixir/test/view_collation_test.exs index 7563ba41644..5f9a2ab97e6 100644 --- a/test/elixir/test/view_collation_test.exs +++ b/test/elixir/test/view_collation_test.exs @@ -8,7 +8,7 @@ defmodule ViewCollationTest do @values [ # Special values sort before all other types - :null, + nil, false, true, @@ -94,7 +94,7 @@ defmodule ViewCollationTest do test "key query option", context do Enum.each(@values, fn value -> retry_until(fn -> - resp = Couch.get(url(context), query: %{:key => :jiffy.encode(value)}) + resp = Couch.get(url(context), query: %{:key => :jiffy.encode(value, [:use_nil])}) assert length(resp.body["rows"]) == 1 assert Enum.at(resp.body["rows"], 0)["key"] == convert(value) end) @@ -139,6 +139,6 @@ defmodule ViewCollationTest do end def convert(value) do - :jiffy.decode(:jiffy.encode(value), [:return_maps]) + :jiffy.decode(:jiffy.encode(value, [:use_nil]), [:return_maps, :use_nil]) end end diff --git a/test/elixir/test/view_errors_test.exs b/test/elixir/test/view_errors_test.exs index d45eb7c3f7f..bf563127774 100644 --- a/test/elixir/test/view_errors_test.exs +++ b/test/elixir/test/view_errors_test.exs @@ -20,7 +20,7 @@ defmodule ViewErrorsTest do # being included in the view results as null results = query(db_name, map_fun) assert results["total_rows"] == 1 - assert Enum.at(results["rows"], 0)["key"] == :null + assert Enum.at(results["rows"], 0)["key"] == nil end @tag :with_db @@ -62,7 +62,7 @@ defmodule ViewErrorsTest do |> Map.get("key") |> Enum.at(1) - assert key == :null + assert key == nil end @tag :with_db diff --git a/test/elixir/test/view_multi_key_all_docs_test.exs b/test/elixir/test/view_multi_key_all_docs_test.exs index d9fa41e2375..4ca64363f18 100644 --- a/test/elixir/test/view_multi_key_all_docs_test.exs +++ b/test/elixir/test/view_multi_key_all_docs_test.exs @@ -27,7 +27,7 @@ defmodule ViewMultiKeyAllDocsTest do test "keys in GET parameters", context do db_name = context[:db_name] - resp = all_docs(db_name, keys: :jiffy.encode(@keys)) + resp = all_docs(db_name, keys: :jiffy.encode(@keys, [:use_nil])) assert resp.status_code == 200 rows = resp.body["rows"] assert length(rows) == length(@keys) @@ -47,7 +47,7 @@ defmodule ViewMultiKeyAllDocsTest do test "keys in GET parameters (limit)", context do db_name = context[:db_name] - resp = all_docs(db_name, limit: 1, keys: :jiffy.encode(@keys)) + resp = all_docs(db_name, limit: 1, keys: :jiffy.encode(@keys, [:use_nil])) assert resp.status_code == 200 rows = resp.body["rows"] assert length(rows) == 1 @@ -68,7 +68,7 @@ defmodule ViewMultiKeyAllDocsTest do test "keys in GET parameters (skip)", context do db_name = context[:db_name] - resp = all_docs(db_name, skip: 2, keys: :jiffy.encode(@keys)) + resp = all_docs(db_name, skip: 2, keys: :jiffy.encode(@keys, [:use_nil])) assert resp.status_code == 200 rows = resp.body["rows"] assert length(rows) == 3 @@ -90,7 +90,7 @@ defmodule ViewMultiKeyAllDocsTest do test "keys in GET parameters (descending)", context do db_name = context[:db_name] - resp = all_docs(db_name, descending: true, keys: :jiffy.encode(@keys)) + resp = all_docs(db_name, descending: true, keys: :jiffy.encode(@keys, [:use_nil])) assert resp.status_code == 200 rows = resp.body["rows"] assert length(rows) == length(@keys) @@ -119,7 +119,7 @@ defmodule ViewMultiKeyAllDocsTest do db_name = context[:db_name] resp = - all_docs(db_name, descending: "true", skip: 3, limit: 1, keys: :jiffy.encode(@keys)) + all_docs(db_name, descending: "true", skip: 3, limit: 1, keys: :jiffy.encode(@keys, [:use_nil])) assert resp.status_code == 200 rows = resp.body["rows"] diff --git a/test/elixir/test/view_multi_key_design_test.exs b/test/elixir/test/view_multi_key_design_test.exs index c33491620e1..0af99b4072e 100644 --- a/test/elixir/test/view_multi_key_design_test.exs +++ b/test/elixir/test/view_multi_key_design_test.exs @@ -53,7 +53,7 @@ defmodule ViewMultiKeyDesignTest do test "keys in GET parameters", context do db_name = context[:db_name] - resp = view(db_name, "test/all_docs", keys: :jiffy.encode(@keys)) + resp = view(db_name, "test/all_docs", keys: :jiffy.encode(@keys, [:use_nil])) rows = resp.body["rows"] assert length(rows) == length(@keys) assert Enum.all?(rows, &Enum.member?(@keys, &1["key"])) @@ -80,7 +80,7 @@ defmodule ViewMultiKeyDesignTest do test "keys in GET body (group)", context do db_name = context[:db_name] - resp = view(db_name, "test/summate", group: true, keys: :jiffy.encode(@keys)) + resp = view(db_name, "test/summate", group: true, keys: :jiffy.encode(@keys, [:use_nil])) rows = resp.body["rows"] assert length(rows) == length(@keys) assert Enum.all?(rows, &Enum.member?(@keys, &1["key"])) @@ -117,10 +117,10 @@ defmodule ViewMultiKeyDesignTest do db_name = context[:db_name] badargs = [ - [startkey: 0, keys: :jiffy.encode(@keys)], - [endkey: 0, keys: :jiffy.encode(@keys)], - [key: 0, keys: :jiffy.encode(@keys)], - [group_level: 2, keys: :jiffy.encode(@keys)] + [startkey: 0, keys: :jiffy.encode(@keys, [:use_nil])], + [endkey: 0, keys: :jiffy.encode(@keys, [:use_nil])], + [key: 0, keys: :jiffy.encode(@keys, [:use_nil])], + [group_level: 2, keys: :jiffy.encode(@keys, [:use_nil])] ] Enum.each(badargs, fn args -> @@ -135,7 +135,7 @@ defmodule ViewMultiKeyDesignTest do resp = Couch.get("/#{db_name}/_design/test/_view/summate", - query: [keys: :jiffy.encode(@keys)], + query: [keys: :jiffy.encode(@keys, [:use_nil])], body: %{"keys" => @keys} ) @@ -148,7 +148,7 @@ defmodule ViewMultiKeyDesignTest do resp = view(db_name, "test/summate", [reduce: false], @keys) assert length(resp.body["rows"]) == 5 - resp = view(db_name, "test/summate", reduce: false, keys: :jiffy.encode(@keys)) + resp = view(db_name, "test/summate", reduce: false, keys: :jiffy.encode(@keys, [:use_nil])) assert length(resp.body["rows"]) == 5 end @@ -191,7 +191,7 @@ defmodule ViewMultiKeyDesignTest do assert length(rows) == 1 assert Enum.at(rows, 0)["key"] == 10 - resp = view(db_name, "test/all_docs", limit: 1, keys: :jiffy.encode(@keys)) + resp = view(db_name, "test/all_docs", limit: 1, keys: :jiffy.encode(@keys, [:use_nil])) rows = resp.body["rows"] assert length(rows) == 1 assert Enum.at(rows, 0)["key"] == 10 diff --git a/test/elixir/test/view_offsets_test.exs b/test/elixir/test/view_offsets_test.exs index edb5a58f66c..34f2aba71db 100644 --- a/test/elixir/test/view_offsets_test.exs +++ b/test/elixir/test/view_offsets_test.exs @@ -51,7 +51,7 @@ defmodule ViewOffsetTest do |> Enum.each(fn [start_key, offset] -> result = view(db_name, "test/offset", %{ - "startkey" => :jiffy.encode(start_key), + "startkey" => :jiffy.encode(start_key, [:use_nil]), "descending" => true })