blob: bea5e1d8c11fdf7fb9f104c14252fee1ff49c979 [file] [log] [blame]
defmodule ViewPartitionTest do
use CouchTestCase
import PartitionHelpers
@moduledoc """
Test Partition functionality for views
"""
@moduletag :partition
@moduletag kind: :cluster
setup_all do
db_name = random_db_name()
{:ok, _} = create_db(db_name, query: %{partitioned: true, q: 1})
on_exit(fn -> delete_db(db_name) end)
create_partition_docs(db_name)
map_fun1 = """
function(doc) {
if (doc.some) {
emit(doc.value, doc.some);
}
}
"""
map_fun2 = """
function(doc) {
if (doc.group) {
emit([doc.some, doc.group], 1);
}
}
"""
query = %{:w => 3}
body = %{
:docs => [
%{
_id: "_design/map",
views: %{some: %{map: map_fun1}}
},
%{
_id: "_design/map_some",
views: %{some: %{map: map_fun2}}
},
%{
_id: "_design/partitioned_true",
views: %{some: %{map: map_fun1}},
options: %{partitioned: true}
},
%{
_id: "_design/partitioned_false",
views: %{some: %{map: map_fun1}},
options: %{partitioned: false}
},
%{
_id: "_design/reduce",
views: %{some: %{map: map_fun2, reduce: "_count"}}
},
%{
_id: "_design/include_ddocs",
views: %{some: %{map: map_fun1}},
options: %{include_design: true}
}
]
}
resp = Couch.post("/#{db_name}/_bulk_docs", query: query, body: body)
Enum.each(resp.body, &assert(&1["ok"]))
{:ok, [db_name: db_name]}
end
def get_reduce_result(resp) do
%{:body => %{"rows" => rows}} = resp
rows
end
test "query with partitioned:true returns partitioned fields", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/partitioned_true/_view/some"
resp = Couch.get(url)
assert resp.status_code == 200
partitions = get_partitions(resp)
assert Enum.dedup(partitions) == ["foo"]
url = "/#{db_name}/_partition/bar/_design/partitioned_true/_view/some"
resp = Couch.get(url)
assert resp.status_code == 200
partitions = get_partitions(resp)
assert Enum.dedup(partitions) == ["bar"]
end
test "default view query returns partitioned fields", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url)
assert resp.status_code == 200
partitions = get_partitions(resp)
assert Enum.dedup(partitions) == ["foo"]
url = "/#{db_name}/_partition/bar/_design/map/_view/some"
resp = Couch.get(url)
assert resp.status_code == 200
partitions = get_partitions(resp)
assert Enum.dedup(partitions) == ["bar"]
end
test "conflicting partitions in path and query string rejected", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{partition: "bar"})
assert resp.status_code == 400
%{:body => %{"reason" => reason}} = resp
assert Regex.match?(~r/Conflicting value/, reason)
end
test "query will return zero results for wrong inputs", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{start_key: "\"foo:12\""})
assert resp.status_code == 200
assert Map.get(resp, :body)["rows"] == []
end
test "partitioned ddoc cannot be used in global query", context do
db_name = context[:db_name]
url = "/#{db_name}/_design/map/_view/some"
resp = Couch.get(url)
%{:body => %{"reason" => reason}} = resp
assert resp.status_code == 400
assert Regex.match?(~r/mandatory for queries to this view./, reason)
end
test "partitioned query cannot be used with global ddoc", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/partitioned_false/_view/some"
resp = Couch.get(url)
%{:body => %{"reason" => reason}} = resp
assert resp.status_code == 400
assert Regex.match?(~r/is not supported in this design doc/, reason)
end
test "view query returns all docs for global query", context do
db_name = context[:db_name]
url = "/#{db_name}/_design/partitioned_false/_view/some"
resp = Couch.get(url)
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 100
end
test "partition query errors with incorrect partition supplied", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/_bar/_design/map/_view/some"
resp = Couch.get(url)
assert resp.status_code == 400
url = "/#{db_name}/_partition//_design/map/_view/some"
resp = Couch.get(url)
assert resp.status_code == 400
end
test "partitioned query works with startkey, endkey range", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{start_key: 12, end_key: 20})
assert resp.status_code == 200
partitions = get_partitions(resp)
assert length(partitions) == 5
assert Enum.dedup(partitions) == ["foo"]
end
test "partitioned query works with keys", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.post(url, body: %{keys: [2, 4, 6]})
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 3
assert ids == ["foo:2", "foo:4", "foo:6"]
end
test "global query works with keys", context do
db_name = context[:db_name]
url = "/#{db_name}/_design/partitioned_false/_view/some"
resp = Couch.post(url, body: %{keys: [2, 4, 6]})
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 3
assert ids == ["foo:2", "foo:4", "foo:6"]
end
test "partition query works with limit", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{limit: 5})
assert resp.status_code == 200
partitions = get_partitions(resp)
assert length(partitions) == 5
assert Enum.dedup(partitions) == ["foo"]
end
test "partition query with descending", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{descending: true, limit: 5})
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 5
assert ids == ["foo:100", "foo:98", "foo:96", "foo:94", "foo:92"]
resp = Couch.get(url, query: %{descending: false, limit: 5})
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 5
assert ids == ["foo:2", "foo:4", "foo:6", "foo:8", "foo:10"]
end
test "partition query with skip", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{skip: 5, limit: 5})
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 5
assert ids == ["foo:12", "foo:14", "foo:16", "foo:18", "foo:20"]
end
test "partition query with key", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map/_view/some"
resp = Couch.get(url, query: %{key: 22})
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 1
assert ids == ["foo:22"]
end
test "partition query with startkey_docid and endkey_docid", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/map_some/_view/some"
resp =
Couch.get(
url,
query: %{
startkey: "[\"field\",\"one\"]",
endkey: "[\"field\",\"one\"]",
startkey_docid: "foo:12",
endkey_docid: "foo:30"
}
)
assert resp.status_code == 200
ids = get_ids(resp)
assert ids == ["foo:12", "foo:18", "foo:24", "foo:30"]
end
test "query with reduce works", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/reduce/_view/some"
resp = Couch.get(url, query: %{reduce: true, group_level: 1})
assert resp.status_code == 200
results = get_reduce_result(resp)
assert results == [%{"key" => ["field"], "value" => 50}]
resp = Couch.get(url, query: %{reduce: true, group_level: 2})
results = get_reduce_result(resp)
assert results == [
%{"key" => ["field", "one"], "value" => 16},
%{"key" => ["field", "two"], "value" => 34}
]
resp = Couch.get(url, query: %{reduce: true, group: true})
results = get_reduce_result(resp)
assert results == [
%{"key" => ["field", "one"], "value" => 16},
%{"key" => ["field", "two"], "value" => 34}
]
end
test "partition query can set query limits", context do
set_config({"query_server_config", "partition_query_limit", "2000"})
db_name = context[:db_name]
create_partition_docs(db_name)
create_partition_ddoc(db_name)
url = "/#{db_name}/_partition/foo/_design/mrtest/_view/some"
resp =
Couch.get(
url,
query: %{
limit: 20
}
)
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 20
resp = Couch.get(url)
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 50
resp =
Couch.get(
url,
query: %{
limit: 2000
}
)
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 50
resp =
Couch.get(
url,
query: %{
limit: 2001
}
)
assert resp.status_code == 400
%{:body => %{"reason" => reason}} = resp
assert Regex.match?(~r/Limit is too large/, reason)
resp =
Couch.get(
url,
query: %{
limit: 2000,
skip: 25
}
)
assert resp.status_code == 200
ids = get_ids(resp)
assert length(ids) == 25
end
test "include_design works correctly", context do
db_name = context[:db_name]
url = "/#{db_name}/_partition/foo/_design/include_ddocs/_view/some"
resp = Couch.get(url)
assert resp.status_code == 200
partitions = get_partitions(resp)
assert length(partitions) == 50
assert Enum.dedup(partitions) == ["foo"]
end
end