summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2023-04-27 14:27:10 +0000
committerGitHub <noreply@github.com>2023-04-27 14:27:10 +0000
commit8e03f97669a15274ea04b9760048f965794ad690 (patch)
tree27d81edfdaf1db629f7da9dcdd40e3f4a4897177
parent0d1175a4f1bfee8b1eb2e2d96a114aac83a2e43b (diff)
parent307450c3c0dcc7a06631d54ccdd5c0ceca191481 (diff)
downloadcouchdb-8e03f97669a15274ea04b9760048f965794ad690.tar.gz
Merge pull request #4543 from apache/jenkins-enable-nouveau-ci
enable nouveau in CI
-rw-r--r--Makefile12
-rw-r--r--build-aux/Jenkinsfile.full29
-rw-r--r--build-aux/Jenkinsfile.pr4
-rw-r--r--nouveau/nouveau.yaml3
-rw-r--r--nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java31
-rw-r--r--nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java2
-rw-r--r--nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java10
-rw-r--r--nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java7
-rw-r--r--src/nouveau/src/nouveau_fabric_info.erl2
-rw-r--r--src/nouveau/src/nouveau_fabric_search.erl4
-rw-r--r--src/nouveau/src/nouveau_httpd.erl2
-rw-r--r--src/nouveau/src/nouveau_maps.erl121
-rw-r--r--test/elixir/test/config/nouveau.elixir4
-rw-r--r--test/elixir/test/config/test-config.ini3
-rw-r--r--test/elixir/test/nouveau_test.exs82
15 files changed, 280 insertions, 36 deletions
diff --git a/Makefile b/Makefile
index 4d7704389..51705f188 100644
--- a/Makefile
+++ b/Makefile
@@ -294,7 +294,11 @@ elixir-source-checks: elixir-init
.PHONY: build-report
# target: build-report - Generate a build report
build-report:
- build-aux/show-test-results.py --suites=10 --tests=10 > test-results.log
+ build-aux/show-test-results.py --suites=10 --tests=10 > test-results.log || true
+ cat ./dev/logs/node1.log || true
+ cat ./dev/logs/nouveau.log || true
+ cat ./tmp/couch.log || true
+ cat test-results.log || true
.PHONY: check-qs
# target: check-qs - Run query server tests (ruby and rspec required!)
@@ -474,7 +478,7 @@ clean:
@rm -f dev/*.beam dev/devnode.* dev/pbkdf2.pyc log/crash.log
@rm -f dev/erlserver.pem dev/couch_ssl_dist.conf
ifeq ($(with_nouveau), 1)
- @cd nouveau && mvn clean
+ @cd nouveau && mvn -B clean
endif
@@ -545,7 +549,7 @@ derived:
# Build nouveau
nouveau:
ifeq ($(with_nouveau), 1)
- @cd nouveau && mvn -D maven.test.skip=true
+ @cd nouveau && mvn -B -D maven.test.skip=true
endif
.PHONY: nouveau-test
@@ -554,7 +558,7 @@ nouveau-test: nouveau-test-maven nouveau-test-elixir
.PHONY: nouveau-test-maven
nouveau-test-maven: couch nouveau
ifeq ($(with_nouveau), 1)
- @cd nouveau && mvn test -P allTests
+ @cd nouveau && mvn -B test -P allTests
endif
.PHONY: nouveau-test-elixir
diff --git a/build-aux/Jenkinsfile.full b/build-aux/Jenkinsfile.full
index 50dec78fc..8f0e9e31e 100644
--- a/build-aux/Jenkinsfile.full
+++ b/build-aux/Jenkinsfile.full
@@ -26,42 +26,49 @@ meta = [
'centos7': [
name: 'CentOS 7',
spidermonkey_vsn: '1.8.5',
+ enable_nouveau: true,
image: "apache/couchdbci-centos:7-erlang-${ERLANG_VERSION}"
],
'centos8': [
name: 'CentOS 8',
spidermonkey_vsn: '60',
+ enable_nouveau: true,
image: "apache/couchdbci-centos:8-erlang-${ERLANG_VERSION}"
],
'bionic': [
name: 'Ubuntu 18.04',
spidermonkey_vsn: '1.8.5',
+ enable_nouveau: true,
image: "apache/couchdbci-ubuntu:bionic-erlang-${ERLANG_VERSION}"
],
'focal': [
name: 'Ubuntu 20.04',
spidermonkey_vsn: '68',
+ enable_nouveau: true,
image: "apache/couchdbci-ubuntu:focal-erlang-${ERLANG_VERSION}"
],
'jammy': [
name: 'Ubuntu 22.04',
spidermonkey_vsn: '91',
+ enable_nouveau: true,
image: "apache/couchdbci-ubuntu:jammy-erlang-${ERLANG_VERSION}"
],
'buster': [
name: 'Debian 10',
spidermonkey_vsn: '60',
+ enable_nouveau: true,
image: "apache/couchdbci-debian:buster-erlang-${ERLANG_VERSION}"
],
'bullseye-arm64': [
name: 'Debian 11 ARM',
spidermonkey_vsn: '78',
+ enable_nouveau: true,
image: "apache/couchdbci-debian:bullseye-erlang-${ERLANG_VERSION}",
node_label: 'arm64v8'
],
@@ -69,6 +76,7 @@ meta = [
'bullseye-ppc64': [
name: 'Debian 11 POWER',
spidermonkey_vsn: '78',
+ enable_nouveau: true,
image: "apache/couchdbci-debian:bullseye-erlang-${ERLANG_VERSION}",
node_label: 'ppc64le'
],
@@ -76,6 +84,7 @@ meta = [
'bullseye-s390x': [
name: 'Debian 11 s390x',
spidermonkey_vsn: '78',
+ enable_nouveau: true,
image: "apache/couchdbci-debian:bullseye-erlang-${ERLANG_VERSION}",
node_label: 's390x'
],
@@ -83,6 +92,7 @@ meta = [
'bullseye': [
name: 'Debian 11',
spidermonkey_vsn: '78',
+ enable_nouveau: true,
image: "apache/couchdbci-debian:bullseye-erlang-${ERLANG_VERSION}"
],
@@ -96,10 +106,19 @@ meta = [
'macos': [
name: 'macOS',
spidermonkey_vsn: '91',
+ enable_nouveau: false,
gnu_make: 'make'
]
]
+def String configure(config) {
+ result = "./configure --skip-deps --spidermonkey-version ${config.spidermonkey_vsn}"
+ if (config.enable_nouveau) {
+ result += " --enable-nouveau"
+ }
+ return result
+}
+
// Credit to https://stackoverflow.com/a/69222555 for this technique.
// We can use the scripted pipeline syntax to dynamically generate stages,
// and inject them into a map that we pass to the `parallel` step in a script.
@@ -130,13 +149,14 @@ def generateNativeStage(platform) {
sh( script: "mkdir -p ${platform}/build", label: 'Create build directories' )
sh( script: "tar -xf apache-couchdb-*.tar.gz -C ${platform}/build --strip-components=1", label: 'Unpack release' )
dir( "${platform}/build" ) {
- sh "./configure --skip-deps --spidermonkey-version ${meta[platform].spidermonkey_vsn}"
+ sh "${configure(meta[platform])}"
sh '$MAKE'
sh '$MAKE eunit'
sh '$MAKE elixir-suite'
sh '$MAKE exunit'
sh '$MAKE mango-test'
sh '$MAKE weatherreport-test'
+ sh '$MAKE nouveau-test'
}
}
}
@@ -183,13 +203,14 @@ def generateContainerStage(platform) {
sh( script: "mkdir -p ${platform}/build", label: 'Create build directories' )
sh( script: "tar -xf apache-couchdb-*.tar.gz -C ${platform}/build --strip-components=1", label: 'Unpack release' )
dir( "${platform}/build" ) {
- sh "./configure --skip-deps --spidermonkey-version ${meta[platform].spidermonkey_vsn}"
+ sh "${configure(meta[platform])}"
sh 'make'
sh 'make eunit'
sh 'make elixir-suite'
sh 'make exunit'
sh 'make mango-test'
sh 'make weatherreport-test'
+ sh 'make nouveau-test'
}
}
catch (err) {
@@ -256,7 +277,7 @@ pipeline {
// We need the jenkins user mapped inside of the image
// npm config cache below deals with /home/jenkins not mapping correctly
// inside the image
- DOCKER_ARGS = '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group'
+ DOCKER_ARGS = '-e npm_config_cache=npm-cache -e HOME=. -v=/etc/passwd:/etc/passwd -v /etc/group:/etc/group -v /root/.m2:/root/.m2'
}
options {
@@ -280,7 +301,7 @@ pipeline {
steps {
timeout(time: 15, unit: "MINUTES") {
sh (script: 'rm -rf apache-couchdb-*', label: 'Clean workspace of any previous release artifacts' )
- sh "./configure --spidermonkey-version 78"
+ sh "./configure --spidermonkey-version 78 --enable-nouveau"
sh 'make dist'
}
}
diff --git a/build-aux/Jenkinsfile.pr b/build-aux/Jenkinsfile.pr
index 4b749e1ac..46c5e47a0 100644
--- a/build-aux/Jenkinsfile.pr
+++ b/build-aux/Jenkinsfile.pr
@@ -20,7 +20,7 @@ mkdir build
cd build
tar -xf ${WORKSPACE}/apache-couchdb-*.tar.gz
cd apache-couchdb-*
-./configure
+./configure --enable-nouveau
make check || (make build-report && false)
'''
@@ -218,7 +218,7 @@ pipeline {
steps {
sh '''
rm -rf apache-couchdb-*
- ./configure --spidermonkey-version 78
+ ./configure --spidermonkey-version 78 --enable-nouveau
make dist
chmod -R a+w * .
'''
diff --git a/nouveau/nouveau.yaml b/nouveau/nouveau.yaml
index 59176bb7a..9e45bd711 100644
--- a/nouveau/nouveau.yaml
+++ b/nouveau/nouveau.yaml
@@ -3,6 +3,9 @@ commitIntervalSeconds: 30
idleSeconds: 60
rootDir: target/indexes
+logging:
+ level: WARN
+
server:
applicationConnectors:
- type: h2c
diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java
index 7d3919c41..3e0f08d64 100644
--- a/nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java
@@ -62,6 +62,37 @@ public class IndexDefinition {
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((defaultAnalyzer == null) ? 0 : defaultAnalyzer.hashCode());
+ result = prime * result + ((fieldAnalyzers == null) ? 0 : fieldAnalyzers.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ IndexDefinition other = (IndexDefinition) obj;
+ if (defaultAnalyzer == null) {
+ if (other.defaultAnalyzer != null)
+ return false;
+ } else if (!defaultAnalyzer.equals(other.defaultAnalyzer))
+ return false;
+ if (fieldAnalyzers == null) {
+ if (other.fieldAnalyzers != null)
+ return false;
+ } else if (!fieldAnalyzers.equals(other.fieldAnalyzers))
+ return false;
+ return true;
+ }
+
+ @Override
public String toString() {
return "IndexDefinition [defaultAnalyzer=" + defaultAnalyzer
+ ", fieldAnalyzers=" + fieldAnalyzers + "]";
diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java
index 7d893a9e2..a08b17816 100644
--- a/nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java
@@ -152,7 +152,7 @@ public abstract class Index implements Closeable {
protected final void assertUpdateSeqIsLower(final long updateSeq) throws UpdatesOutOfOrderException {
assert Thread.holdsLock(this);
if (!(updateSeq > this.updateSeq)) {
- throw new UpdatesOutOfOrderException();
+ throw new UpdatesOutOfOrderException(this.updateSeq, updateSeq);
}
}
diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java
index ddc7c3f7f..f662780bb 100644
--- a/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java
@@ -125,8 +125,13 @@ public final class IndexManager implements Managed {
}
}
- public void create(final String name, IndexDefinition indexDefinition) throws IOException {
+ public void create(final String name, IndexDefinition newIndexDefinition) throws IOException {
if (exists(name)) {
+ final IndexDefinition currentIndexDefinition = loadIndexDefinition(name);
+ if (newIndexDefinition.equals(currentIndexDefinition)) {
+ // Idempotent success.
+ return;
+ }
throw new WebApplicationException("Index already exists", Status.EXPECTATION_FAILED);
}
// Validate index definiton
@@ -134,11 +139,12 @@ public final class IndexManager implements Managed {
// Persist definition
final Path path = indexDefinitionPath(name);
+
if (Files.exists(path)) {
throw new FileAlreadyExistsException(name + " already exists");
}
Files.createDirectories(path.getParent());
- objectMapper.writeValue(path.toFile(), indexDefinition);
+ objectMapper.writeValue(path.toFile(), newIndexDefinition);
}
public boolean exists(final String name) {
diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java
index 3b89f41d2..fe7c1b899 100644
--- a/nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java
@@ -15,10 +15,11 @@ package org.apache.couchdb.nouveau.core;
import java.io.IOException;
-public class UpdatesOutOfOrderException extends IOException {
+public final class UpdatesOutOfOrderException extends IOException {
- public UpdatesOutOfOrderException() {
- super("Updates applied in the wrong order");
+ public UpdatesOutOfOrderException(final long currentSeq, final long attemptedSeq) {
+ super(String.format("Updates applied in the wrong order (current seq: %d, attempted seq: %d)",
+ currentSeq, attemptedSeq));
}
}
diff --git a/src/nouveau/src/nouveau_fabric_info.erl b/src/nouveau/src/nouveau_fabric_info.erl
index 59e47094f..b5f928075 100644
--- a/src/nouveau/src/nouveau_fabric_info.erl
+++ b/src/nouveau/src/nouveau_fabric_info.erl
@@ -70,7 +70,7 @@ handle_message({ok, Info}, Worker, {Counters, Acc0}) ->
nil ->
C1 = fabric_dict:store(Worker, ok, Counters),
C2 = fabric_view:remove_overlapping_shards(Worker, C1),
- Acc1 = maps:merge_with(fun merge_info/3, Info, Acc0),
+ Acc1 = nouveau_maps:merge_with(fun merge_info/3, Info, Acc0),
case fabric_dict:any(nil, C2) of
true ->
{ok, {C2, Acc1}};
diff --git a/src/nouveau/src/nouveau_fabric_search.erl b/src/nouveau/src/nouveau_fabric_search.erl
index 4e528cc93..ca101ba9c 100644
--- a/src/nouveau/src/nouveau_fabric_search.erl
+++ b/src/nouveau/src/nouveau_fabric_search.erl
@@ -217,5 +217,5 @@ merge_facets(FacetsA, null, _Limit) ->
merge_facets(null, FacetsB, _Limit) ->
FacetsB;
merge_facets(FacetsA, FacetsB, _Limit) ->
- Combiner = fun(_, V1, V2) -> maps:merge_with(fun(_, V3, V4) -> V3 + V4 end, V1, V2) end,
- maps:merge_with(Combiner, FacetsA, FacetsB).
+ Combiner = fun(_, V1, V2) -> nouveau_maps:merge_with(fun(_, V3, V4) -> V3 + V4 end, V1, V2) end,
+ nouveau_maps:merge_with(Combiner, FacetsA, FacetsB).
diff --git a/src/nouveau/src/nouveau_httpd.erl b/src/nouveau/src/nouveau_httpd.erl
index 999acc7ea..8d27048a1 100644
--- a/src/nouveau/src/nouveau_httpd.erl
+++ b/src/nouveau/src/nouveau_httpd.erl
@@ -200,7 +200,7 @@ validate_query_arg(sort, Sort) ->
validate_query_arg(ranges, undefined) ->
null;
validate_query_arg(ranges, {json, Ranges}) when is_map(Ranges) ->
- maps:foreach(fun is_valid_range/2, Ranges),
+ nouveau_maps:foreach(fun is_valid_range/2, Ranges),
Ranges;
validate_query_arg(ranges, Ranges) ->
validate_query_arg(ranges, {json, ?JSON_DECODE(Ranges, [return_maps])});
diff --git a/src/nouveau/src/nouveau_maps.erl b/src/nouveau/src/nouveau_maps.erl
new file mode 100644
index 000000000..81a145557
--- /dev/null
+++ b/src/nouveau/src/nouveau_maps.erl
@@ -0,0 +1,121 @@
+%%
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2021. All Rights Reserved.
+%%
+%% 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.
+%%
+%% %CopyrightEnd%
+%%
+
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+
+%% backport of OTP 24 map functions not present in 23.
+
+-module(nouveau_maps).
+
+-export([merge_with/3, foreach/2]).
+
+-if(?OTP_RELEASE >= 24).
+merge_with(Combiner, Map1, Map2) ->
+ maps:merge_with(Combiner, Map1, Map2).
+
+foreach(Fun, MapOrIter) ->
+ maps:foreach(Fun, MapOrIter).
+
+-else.
+
+merge_with(Combiner, Map1, Map2) when
+ is_map(Map1),
+ is_map(Map2),
+ is_function(Combiner, 3)
+->
+ case map_size(Map1) > map_size(Map2) of
+ true ->
+ Iterator = maps:iterator(Map2),
+ merge_with_1(
+ maps:next(Iterator),
+ Map1,
+ Map2,
+ Combiner
+ );
+ false ->
+ Iterator = maps:iterator(Map1),
+ merge_with_1(
+ maps:next(Iterator),
+ Map2,
+ Map1,
+ fun(K, V1, V2) -> Combiner(K, V2, V1) end
+ )
+ end;
+merge_with(Combiner, Map1, Map2) ->
+ error_with_info(
+ error_type_merge_intersect(Map1, Map2, Combiner),
+ [Combiner, Map1, Map2]
+ ).
+
+merge_with_1({K, V2, Iterator}, Map1, Map2, Combiner) ->
+ case Map1 of
+ #{K := V1} ->
+ NewMap1 = Map1#{K := Combiner(K, V1, V2)},
+ merge_with_1(maps:next(Iterator), NewMap1, Map2, Combiner);
+ #{} ->
+ merge_with_1(maps:next(Iterator), maps:put(K, V2, Map1), Map2, Combiner)
+ end;
+merge_with_1(none, Result, _, _) ->
+ Result.
+
+foreach(Fun, MapOrIter) when is_function(Fun, 2) ->
+ Iter =
+ if
+ is_map(MapOrIter) -> maps:iterator(MapOrIter);
+ true -> MapOrIter
+ end,
+ try maps:next(Iter) of
+ Next ->
+ foreach_1(Fun, Next)
+ catch
+ error:_ ->
+ error_with_info({badmap, MapOrIter}, [Fun, MapOrIter])
+ end;
+foreach(Pred, Map) ->
+ badarg_with_info([Pred, Map]).
+
+foreach_1(Fun, {K, V, Iter}) ->
+ Fun(K, V),
+ foreach_1(Fun, maps:next(Iter));
+foreach_1(_Fun, none) ->
+ ok.
+
+%% We must inline these functions so that the stacktrace points to
+%% the correct function.
+-compile({inline, [badarg_with_info/1, error_with_info/2]}).
+
+badarg_with_info(Args) ->
+ erlang:error(badarg, Args, [{error_info, #{module => erl_stdlib_errors}}]).
+
+error_with_info(Reason, Args) ->
+ erlang:error(Reason, Args, [{error_info, #{module => erl_stdlib_errors}}]).
+
+error_type_two_maps(M1, M2) when is_map(M1) ->
+ {badmap, M2};
+error_type_two_maps(M1, _M2) ->
+ {badmap, M1}.
+
+error_type_merge_intersect(M1, M2, Combiner) when is_function(Combiner, 3) ->
+ error_type_two_maps(M1, M2);
+error_type_merge_intersect(_M1, _M2, _Combiner) ->
+ badarg.
+
+-endif.
diff --git a/test/elixir/test/config/nouveau.elixir b/test/elixir/test/config/nouveau.elixir
index 90390a9d6..fdcc66de2 100644
--- a/test/elixir/test/config/nouveau.elixir
+++ b/test/elixir/test/config/nouveau.elixir
@@ -12,6 +12,8 @@
"sort by numeric field (desc)",
"counts",
"ranges",
- "ranges (open)"
+ "ranges (open)",
+ "mango search by number",
+ "mango search by string"
]
}
diff --git a/test/elixir/test/config/test-config.ini b/test/elixir/test/config/test-config.ini
index fb47c5a4c..423cc492c 100644
--- a/test/elixir/test/config/test-config.ini
+++ b/test/elixir/test/config/test-config.ini
@@ -1,3 +1,6 @@
+[log]
+level = warn
+
[chttpd]
authentication_handlers = {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
diff --git a/test/elixir/test/nouveau_test.exs b/test/elixir/test/nouveau_test.exs
index ee5d20542..896ff6154 100644
--- a/test/elixir/test/nouveau_test.exs
+++ b/test/elixir/test/nouveau_test.exs
@@ -22,6 +22,7 @@ defmodule NouveauTest do
def create_ddoc(db_name, opts \\ %{}) do
default_ddoc = %{
+ autoupdate: false,
nouveau: %{
bar: %{
default_analyzer: "standard",
@@ -42,22 +43,47 @@ defmodule NouveauTest do
assert Map.has_key?(resp.body, "ok") == true
end
+ def create_mango_index(db_name) do
+ body = %{
+ type: "nouveau",
+ index: %{
+ fields: [
+ %{name: "foo", type: "string"},
+ %{name: "bar", type: "number"}
+ ]
+ }
+ }
+
+ resp = Couch.post("/#{db_name}/_index", body: body)
+ assert resp.status_code in [200]
+ end
+
def get_ids(resp) do
%{:body => %{"hits" => hits}} = resp
Enum.map(hits, fn hit -> hit["doc"]["_id"] end)
end
+ def get_mango_ids(resp) do
+ %{:body => %{"docs" => docs}} = resp
+ Enum.map(docs, fn doc -> doc["_id"] end)
+ end
+
def get_bookmark(resp) do
%{:body => %{"bookmark" => bookmark}} = resp
bookmark
end
+ def assert_status_code(resp, code) do
+ assert resp.status_code == code,
+ "status code: #{resp.status_code}, resp body: #{:jiffy.encode(resp.body)}"
+ end
+
test "search analyze", context do
url = "/_nouveau_analyze"
resp = Couch.post(url,
headers: ["Content-Type": "application/json"],
body: %{analyzer: "standard", text: "hello there"})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
assert resp.body == %{"tokens" => ["hello", "there"]}
end
@@ -70,11 +96,11 @@ defmodule NouveauTest do
# query it so it builds
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.get(url, query: %{q: "*:*", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
url = "/#{db_name}/_design/foo/_nouveau_info/bar"
resp = Couch.get(url)
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
info = Map.get(resp.body, "search_index")
assert Map.get(info, "disk_size") > 0
assert Map.get(info, "num_docs") > 0
@@ -89,7 +115,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.get(url, query: %{q: "*:*", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
# nouveau sorts by _id as tie-breaker
assert ids == ["doc1", "doc2", "doc3", "doc4"]
@@ -103,7 +129,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "*:*", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc1", "doc2", "doc3", "doc4"]
end
@@ -118,13 +144,13 @@ defmodule NouveauTest do
# page 1
resp = Couch.post(url, body: %{q: "*:*", limit: 2, include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc1", "doc2"]
# page 2
resp = Couch.post(url, body: %{q: "*:*", limit: 2, bookmark: get_bookmark(resp), include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc3", "doc4"]
end
@@ -137,7 +163,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "foo:bar", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc3"]
end
@@ -150,7 +176,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "*:*", sort: "foo<string>", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc3", "doc1", "doc4", "doc2"]
end
@@ -163,7 +189,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "*:*", sort: "-foo<string>", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc2", "doc4", "doc1", "doc3"]
end
@@ -176,7 +202,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "*:*", sort: "bar<double>", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc1", "doc3", "doc4", "doc2"]
end
@@ -189,7 +215,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "*:*", sort: "-bar<double>", include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
ids = get_ids(resp)
assert ids == ["doc2", "doc4", "doc3", "doc1"]
end
@@ -202,7 +228,7 @@ defmodule NouveauTest do
url = "/#{db_name}/_design/foo/_nouveau/bar"
resp = Couch.post(url, body: %{q: "*:*", counts: ["foo"], include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
%{:body => %{"counts" => counts}} = resp
assert counts == %{"foo" => %{"bar" => 1, "baz" => 1, "foo" => 1, "foobar" => 1}}
end
@@ -218,7 +244,7 @@ defmodule NouveauTest do
%{label: "cheap", min: 0, max: 42},
%{label: "expensive", min: 42, min_inclusive: false, max: 1000}]},
include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
%{:body => %{"ranges" => ranges}} = resp
assert ranges == %{"bar" => %{"cheap" => 3, "expensive" => 1}}
end
@@ -234,9 +260,35 @@ defmodule NouveauTest do
%{label: "cheap", max: 42},
%{label: "expensive", min: 42, min_inclusive: false}]},
include_docs: true})
- assert resp.status_code == 200, "error #{resp.status_code} #{:jiffy.encode(resp.body)}"
+ assert_status_code(resp, 200)
%{:body => %{"ranges" => ranges}} = resp
assert ranges == %{"bar" => %{"cheap" => 3, "expensive" => 1}}
end
+ @tag :with_db
+ test "mango search by number", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_mango_index(db_name)
+
+ url = "/#{db_name}/_find"
+ resp = Couch.post(url, body: %{selector: %{bar: %{"$gt": 5}}})
+ assert_status_code(resp, 200)
+ ids = get_mango_ids(resp)
+ assert ids == ["doc2", "doc3", "doc4"]
+ end
+
+ @tag :with_db
+ test "mango search by string", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_mango_index(db_name)
+
+ url = "/#{db_name}/_find"
+ resp = Couch.post(url, body: %{selector: %{foo: %{"$eq": "foo"}}})
+ assert_status_code(resp, 200)
+ ids = get_mango_ids(resp)
+ assert ids == ["doc4"]
+ end
+
end