You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ch...@apache.org on 2017/12/08 21:05:11 UTC

[couchdb] branch elixir-suite updated (1edae17 -> 6895fdc)

This is an automated email from the ASF dual-hosted git repository.

chewbranca pushed a change to branch elixir-suite
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


    from 1edae17  Port config.js tests
     add a9123ae  Add support for a config tag
     add 5c5b60b  Port uuids.js to Elixir
     add 4898c08  Remove module attribute
     add 44516be  Add simple Makefile for muscle memory
     add 7e10c70  Simple .gitignore for sanity
     add b52f778  Ignore erln8.config
     add 1e0cb25  DRY constant definition
     add 67f6fae  Update the context in place for setup
     add 7b8e6c1  Embrace the Elixir
     add 86708b5  Port view_collation.js to view_collation_test.exs
     new 7aba50b  Remove extraneous comment
     new 6895fdc  Port reduce.js suite

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                |   1 +
 elixir_suite/.gitignore                   |   2 +
 elixir_suite/Makefile                     |   2 +
 elixir_suite/test/reduce_test.exs         | 430 ++++++++++++++++++++++++++++++
 elixir_suite/test/test_helper.exs         |  83 ++++--
 elixir_suite/test/uuids_test.exs          |  94 +++++++
 elixir_suite/test/view_collation_test.exs | 133 +++++++++
 7 files changed, 725 insertions(+), 20 deletions(-)
 create mode 100644 elixir_suite/.gitignore
 create mode 100644 elixir_suite/Makefile
 create mode 100644 elixir_suite/test/reduce_test.exs
 create mode 100644 elixir_suite/test/uuids_test.exs
 create mode 100644 elixir_suite/test/view_collation_test.exs

-- 
To stop receiving notification emails like this one, please contact
['"commits@couchdb.apache.org" <co...@couchdb.apache.org>'].

[couchdb] 01/02: Remove extraneous comment

Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

chewbranca pushed a commit to branch elixir-suite
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 7aba50bdaee685ff7bc8cd0dc6271eed96aa2f9f
Author: Russell Branca <ch...@apache.org>
AuthorDate: Thu Dec 7 18:40:19 2017 +0000

    Remove extraneous comment
---
 elixir_suite/test/test_helper.exs | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/elixir_suite/test/test_helper.exs b/elixir_suite/test/test_helper.exs
index cef7d13..1c61e4a 100644
--- a/elixir_suite/test/test_helper.exs
+++ b/elixir_suite/test/test_helper.exs
@@ -1,11 +1,6 @@
 ExUnit.configure(exclude: [pending: true])
 ExUnit.start()
 
-# TODO
-#def random_db_name do
-#  "asdf"
-#end
-
 defmodule CouchTestCase do
   use ExUnit.Case
 

-- 
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <co...@couchdb.apache.org>.

[couchdb] 02/02: Port reduce.js suite

Posted by ch...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

chewbranca pushed a commit to branch elixir-suite
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 6895fdc8b6a4147fa1a91119e701789657955376
Author: Russell Branca <ch...@apache.org>
AuthorDate: Fri Dec 8 20:56:24 2017 +0000

    Port reduce.js suite
---
 elixir_suite/test/reduce_test.exs | 430 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 430 insertions(+)

diff --git a/elixir_suite/test/reduce_test.exs b/elixir_suite/test/reduce_test.exs
new file mode 100644
index 0000000..a01c997
--- /dev/null
+++ b/elixir_suite/test/reduce_test.exs
@@ -0,0 +1,430 @@
+defmodule ReduceTest do
+  use CouchTestCase
+
+  @moduletag :views
+
+  @moduledoc """
+  Test CouchDB view reduces
+  This is a port of the reduce.js suite
+  """
+
+  def summate(n) do
+    (n + 1) * n / 2
+  end
+
+  def make_docs(id, count) do
+    for i <- id..count do
+      %{
+        :_id => Integer.to_string(i),
+        :integer => i,
+        :string => Integer.to_string(i)
+      }
+    end
+  end
+
+  @tag :with_db
+  test "Basic reduce functions", context do
+    db_name = context[:db_name]
+    view_url = "/#{db_name}/_design/foo/_view/bar"
+    num_docs = 500
+    map = ~s"""
+function (doc) {
+  emit(doc.integer, doc.integer);
+  emit(doc.integer, doc.integer);
+};
+    """
+    reduce = "function (keys, values) { return sum(values); };"
+    red_doc = %{:views => %{:bar => %{:map => map, :reduce => reduce}}}
+
+    assert Couch.put("/#{db_name}/_design/foo", [body: red_doc]).body["ok"]
+    docs = make_docs(1, num_docs)
+    assert Couch.post("/#{db_name}/_bulk_docs", [body: %{:docs => docs}]).status_code == 201
+    :timer.sleep(200) # *sigh*
+
+    rows = Couch.get(view_url).body["rows"]
+    assert hd(rows)["value"] == 2 * summate(num_docs)
+
+    query = %{:startkey => 4, :endkey => 4}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 8
+
+    query = %{:startkey => 4, :endkey => 5}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 18
+
+    query = %{:startkey => 4, :endkey => 6}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 30
+
+    query = %{:group => true, :limit => 3}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert Enum.at(rows, 0)["value"] == 2
+    assert Enum.at(rows, 1)["value"] == 4
+    assert Enum.at(rows, 2)["value"] == 6
+
+    half_num_docs = Integer.floor_div(num_docs, 2)
+    max = Integer.floor_div(num_docs, 30) + 1
+    for i <- 1..max, i * 30 + 1 < half_num_docs do
+      i = i * 30 + 1
+      query = %{:startkey => i, :endkey => num_docs - i}
+      rows = Couch.get(view_url, query: query).body["rows"]
+      assert hd(rows)["value"] == 2 * (summate(num_docs - i) - summate(i - 1))
+    end
+  end
+
+  @tag :with_db
+  test "More complex array key view row testing", context do
+    db_name = context[:db_name]
+    view_url = "/#{db_name}/_design/foo/_view/bar"
+    map = "function (doc) { emit(doc.keys, 1); };"
+    reduce = "function (keys, values) { return sum(values); };"
+    red_doc = %{:views => %{bar: %{map: map, reduce: reduce}}}
+
+    assert Couch.put("/#{db_name}/_design/foo", [body: red_doc]).body["ok"]
+    for i <- 1..5 do
+      for j <- 0..9 do
+        docs = [
+          %{keys: ["a"]},
+          %{keys: ["a"]},
+          %{keys: ["a", "b"]},
+          %{keys: ["a", "b"]},
+          %{keys: ["a", "b", "c"]},
+          %{keys: ["a", "b", "d"]},
+          %{keys: ["a", "c", "d"]},
+          %{keys: ["d"]},
+          %{keys: ["d", "a"]},
+          %{keys: ["d", "b"]},
+          %{keys: ["d", "c"]}
+        ]
+        assert Couch.post("/#{db_name}/_bulk_docs", [body: %{docs: docs}]).status_code == 201
+        :timer.sleep(20) # *sigh*
+        total_docs = 1 + ((i - 1) * 10 * 11) + ((j + 1) * 11);
+        assert Couch.get("/#{db_name}").body["doc_count"] == total_docs
+      end
+
+      # test group by exact key match
+      query = %{group: true}
+      rows = Couch.get(view_url, query: query).body["rows"]
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20 * i}
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20 * i}
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20 * i}
+      assert Enum.at(rows, 1) == %{"key" => ["a", "b"], "value" => 20 * i}
+      assert Enum.at(rows, 2) == %{"key" => ["a", "b", "c"], "value" => 10 * i}
+      assert Enum.at(rows, 3) == %{"key" => ["a", "b", "d"], "value" => 10 * i}
+
+      # test group reduce and limit params provide valid json
+      query = %{group: true, limit: 2}
+      rows = Couch.get(view_url, query: query).body["rows"]
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20 * i}
+      assert length(rows) == 2
+
+      # test group by the first element in the key array
+      query = %{group_level: 2}
+      rows = Couch.get(view_url, query: query).body["rows"]
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20*i}
+      assert Enum.at(rows, 1) == %{"key" => ["a","b"], "value" => 40*i}
+      assert Enum.at(rows, 2) == %{"key" => ["a","c"], "value" => 10*i}
+      assert Enum.at(rows, 3) == %{"key" => ["d"], "value" => 10*i}
+      assert Enum.at(rows, 4) == %{"key" => ["d","a"], "value" => 10*i}
+      assert Enum.at(rows, 5) == %{"key" => ["d","b"], "value" => 10*i}
+      assert Enum.at(rows, 6) == %{"key" => ["d","c"], "value" => 10*i}
+
+      # test endkey with inclusive_end=true
+      query = %{group_level: 2, endkey: ~s(["d"]), inclusive_end: true}
+      rows = Couch.get(view_url, query: query).body["rows"]
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20*i}
+      assert Enum.at(rows, 1) == %{"key" => ["a","b"], "value" => 40*i}
+      assert Enum.at(rows, 2) == %{"key" => ["a","c"], "value" => 10*i}
+      assert Enum.at(rows, 3) == %{"key" => ["d"], "value" => 10*i}
+      assert length(rows) == 4
+
+      # test endkey with inclusive_end=false
+      query = %{group_level: 2, endkey: ~s(["d"]), inclusive_end: false}
+      rows = Couch.get(view_url, query: query).body["rows"]
+      assert Enum.at(rows, 0) == %{"key" => ["a"], "value" => 20*i}
+      assert Enum.at(rows, 1) == %{"key" => ["a","b"], "value" => 40*i}
+      assert Enum.at(rows, 2) == %{"key" => ["a","c"], "value" => 10*i}
+      assert length(rows) == 3
+    end
+  end
+
+  @tag :with_db
+  test "More complex reductions that need to use the combine option", context do
+    db_name = context[:db_name]
+    view_url = "/#{db_name}/_design/foo/_view/bar"
+    map = "function (doc) { emit(doc.val, doc.val); };"
+    reduce = ~s"""
+function (keys, values, rereduce) {
+    // This computes the standard deviation of the mapped results
+    var stdDeviation=0.0;
+    var count=0;
+    var total=0.0;
+    var sqrTotal=0.0;
+
+    if (!rereduce) {
+      // This is the reduce phase, we are reducing over emitted values from
+      // the map functions.
+      for(var i in values) {
+        total = total + values[i];
+        sqrTotal = sqrTotal + (values[i] * values[i]);
+      }
+      count = values.length;
+    }
+    else {
+      // This is the rereduce phase, we are re-reducing previosuly
+      // reduced values.
+      for(var i in values) {
+        count = count + values[i].count;
+        total = total + values[i].total;
+        sqrTotal = sqrTotal + values[i].sqrTotal;
+      }
+    }
+
+    var variance =  (sqrTotal - ((total * total)/count)) / count;
+    stdDeviation = Math.sqrt(variance);
+
+    // the reduce result. It contains enough information to be rereduced
+    // with other reduce results.
+    return {"stdDeviation":stdDeviation,"count":count,
+        "total":total,"sqrTotal":sqrTotal};
+}
+    """
+
+    red_doc = %{:views => %{:bar => %{:map => map, :reduce => reduce}}}
+    assert Couch.put("/#{db_name}/_design/foo", [body: red_doc]).body["ok"]
+
+    Enum.each(1..10, fn _ ->
+      docs = for i <- 1..10, do: %{val: i * 10}
+      assert Couch.post("/#{db_name}/_bulk_docs", [body: %{:docs => docs}]).status_code == 201
+    end)
+    :timer.sleep(200) # *sigh*
+
+    rows = Couch.get(view_url).body["rows"]
+    assert_in_delta hd(rows)["value"]["stdDeviation"], 28.722813232690143, 0.0000000001
+  end
+
+  @tag :with_db
+  test "Reduce pagination", context do
+    db_name = context[:db_name]
+    view_url = "/#{db_name}/_design/foo/_view/bar"
+    ddoc = %{
+      _id: "_design/foo",
+      language: "javascript",
+      views: %{
+        bar: %{
+          reduce: "_count",
+          map: ~s"""
+            function(doc) {
+               emit(doc.int, doc._id);
+               emit(doc.int + 1, doc._id);
+               emit(doc.int + 2, doc._id);
+            }
+          """
+        }
+      }
+    }
+
+    assert Couch.put("/#{db_name}/_design/foo", [body: ddoc]).body["ok"]
+    docs = for i <- 0..1122, do: %{_id: Integer.to_string(i), int: i}
+    assert Couch.post("/#{db_name}/_bulk_docs", [body: %{:docs => docs}]).status_code == 201
+    :timer.sleep(200) # *sigh*
+
+    rand_val = fn -> :rand.uniform(100000000) end
+
+    # ?group=false tests
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.()}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 9
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 9
+
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 6
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), inclusive_end: false, descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 6
+
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "400"}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 7
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "400", inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 6
+
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "401"}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 8
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "401", inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 7
+
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "402"}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 9
+    query = %{startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "402", inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 8
+
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "398", descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 9
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "398", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 8
+
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "399", descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 8
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "399", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 7
+
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "400", descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 7
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "400", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 6
+
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), startkey_docid: "400", descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 7
+
+    query = %{startkey: 402, endkey: 400, foobar: rand_val.(), startkey_docid: "401", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert hd(rows)["value"] == 5
+
+    # ?group=true tests
+    query = %{:group => true, startkey: 400, endkey: 402, foobar: rand_val.()}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 400
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 402
+    assert Enum.at(rows, 2)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 400
+    assert Enum.at(rows, 2)["value"] == 3
+
+    query = %{:group => true, startkey: 400, endkey: 402, foobar: rand_val.(), inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 2
+    assert Enum.at(rows, 0)["key"] == 400
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), inclusive_end: false, descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 2
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+
+    query = %{:group => true, startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "401"}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 400
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 402
+    assert Enum.at(rows, 2)["value"] == 2
+
+    query = %{:group => true, startkey: 400, endkey: 402, foobar: rand_val.(), endkey_docid: "400"}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 400
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 402
+    assert Enum.at(rows, 2)["value"] == 1
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), startkey_docid: "401", descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 2
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 400
+    assert Enum.at(rows, 2)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), startkey_docid: "400", descending: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 1
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 400
+    assert Enum.at(rows, 2)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), startkey_docid: "401", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 2
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 2
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), startkey_docid: "400", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 2
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 1
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "398", descending: true, inclusive_end: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 400
+    assert Enum.at(rows, 2)["value"] == 3
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "399", descending: true, inclusive_end: true}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 400
+    assert Enum.at(rows, 2)["value"] == 2
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "399", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 3
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+    assert Enum.at(rows, 2)["key"] == 400
+    assert Enum.at(rows, 2)["value"] == 1
+
+    query = %{:group => true, startkey: 402, endkey: 400, foobar: rand_val.(), endkey_docid: "400", descending: true, inclusive_end: false}
+    rows = Couch.get(view_url, query: query).body["rows"]
+    assert length(rows) == 2
+    assert Enum.at(rows, 0)["key"] == 402
+    assert Enum.at(rows, 0)["value"] == 3
+    assert Enum.at(rows, 1)["key"] == 401
+    assert Enum.at(rows, 1)["value"] == 3
+  end
+end

-- 
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <co...@couchdb.apache.org>.