You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2019/02/21 19:26:50 UTC

[couchdb] branch master updated: Fix elixir tests on Jenkins (#1931)

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

garren pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/master by this push:
     new d9d2375  Fix elixir tests on Jenkins (#1931)
d9d2375 is described below

commit d9d2375d203421c0e81b5186f9a95515af963529
Author: garren smith <ga...@gmail.com>
AuthorDate: Thu Feb 21 21:26:45 2019 +0200

    Fix elixir tests on Jenkins (#1931)
    
    fix flaky  elixir tests on jenkins
    
    * Add retry_until to some flaky tests.
    * Add skip_on_jenkins tag for tests that won't pass with retry_until but pass on Travis.
    * set jenkins timeout to 90 minutes
---
 Jenkinsfile                                     | 16 ++---
 test/elixir/lib/couch/db_test.ex                |  4 +-
 test/elixir/test/all_docs_test.exs              |  6 +-
 test/elixir/test/bulk_docs_test.exs             | 32 +++++----
 test/elixir/test/coffee_test.exs                |  7 +-
 test/elixir/test/compact_test.exs               |  1 +
 test/elixir/test/lots_of_docs_test.exs          | 21 +++---
 test/elixir/test/partition_ddoc_test.exs        |  1 +
 test/elixir/test/partition_size_test.exs        |  1 +
 test/elixir/test/partition_view_update_test.exs |  1 +
 test/elixir/test/replication_test.exs           | 89 ++++++++++++++++---------
 test/elixir/test/security_validation_test.exs   | 10 +--
 test/elixir/test/test_helper.exs                | 10 ++-
 test/elixir/test/view_collation_test.exs        | 28 +++++---
 14 files changed, 141 insertions(+), 86 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index b793343..3488c6e 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -80,7 +80,7 @@ pipeline {
       steps {
         parallel(freebsd: {
           node(label: 'couchdb && freebsd') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               deleteDir()
               unstash 'tarball'
               withEnv(['HOME='+pwd()]) {
@@ -105,7 +105,7 @@ pipeline {
         },
         centos6: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/centos-6-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/centos-6-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
@@ -144,7 +144,7 @@ pipeline {
         },
         centos7: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/centos-7-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/centos-7-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
@@ -183,7 +183,7 @@ pipeline {
         },
         ubuntutrusty: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/ubuntu-trusty-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/ubuntu-trusty-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
@@ -222,7 +222,7 @@ pipeline {
         },
         ubuntuxenial: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/ubuntu-xenial-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/ubuntu-xenial-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
@@ -261,7 +261,7 @@ pipeline {
         },
         ubuntubionic: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/ubuntu-bionic-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/ubuntu-bionic-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
@@ -300,7 +300,7 @@ pipeline {
         },
         debianjessie: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/debian-jessie-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/debian-jessie-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
@@ -339,7 +339,7 @@ pipeline {
         },
         debianstretch: {
           node(label: 'ubuntu') {
-            timeout(time: 60, unit: "MINUTES") {
+            timeout(time: 90, unit: "MINUTES") {
               sh 'docker pull couchdbdev/debian-stretch-erlang-19.3.6'
               withDockerContainer(image: 'couchdbdev/debian-stretch-erlang-19.3.6') {
                 sh 'rm -f apache-couchdb-*.tar.gz'
diff --git a/test/elixir/lib/couch/db_test.ex b/test/elixir/lib/couch/db_test.ex
index 54e6942..f835b0a 100644
--- a/test/elixir/lib/couch/db_test.ex
+++ b/test/elixir/lib/couch/db_test.ex
@@ -214,8 +214,8 @@ defmodule Couch.DBTest do
       raise "timed out after #{now - start} ms"
     else
       try do
-        if condition.() do
-          :ok
+        if result = condition.() do
+          result
         else
           raise ExUnit.AssertionError
         end
diff --git a/test/elixir/test/all_docs_test.exs b/test/elixir/test/all_docs_test.exs
index b8f21e7..9f6aeb6 100644
--- a/test/elixir/test/all_docs_test.exs
+++ b/test/elixir/test/all_docs_test.exs
@@ -41,8 +41,10 @@ defmodule AllDocsTest do
     assert resp["total_rows"] == length(rows)
 
     # Check _all_docs offset
-    resp = Couch.get("/#{db_name}/_all_docs", query: %{:startkey => "\"2\""}).body
-    assert resp["offset"] == 2
+    retry_until(fn ->
+      resp = Couch.get("/#{db_name}/_all_docs", query: %{:startkey => "\"2\""}).body
+      assert resp["offset"] == 2
+    end)
 
     # Confirm that queries may assume raw collation
     resp =
diff --git a/test/elixir/test/bulk_docs_test.exs b/test/elixir/test/bulk_docs_test.exs
index 01a3993..dd92025 100644
--- a/test/elixir/test/bulk_docs_test.exs
+++ b/test/elixir/test/bulk_docs_test.exs
@@ -44,6 +44,7 @@ defmodule BulkDocsTest do
   end
 
   @tag :with_db
+  @tag :skip_on_jenkins
   test "bulk docs can detect conflicts", ctx do
     db = ctx[:db_name]
     docs = create_docs(@doc_range)
@@ -56,13 +57,16 @@ defmodule BulkDocsTest do
     assert resp.status_code == 201
     # Attempt to delete all docs
     docs = Enum.map(docs, fn doc -> Map.put(doc, :_deleted, true) end)
-    resp = bulk_post(docs, db)
-    # Confirm first doc not updated, and result has no rev field
-    res = hd(resp.body)
-    assert res["id"] == "1" and res["error"] == "conflict"
-    assert Map.get(res, "rev") == nil
-    # Confirm other docs updated normally
-    assert revs_start_with(tl(resp.body), "2-")
+
+    retry_until(fn ->
+      resp = bulk_post(docs, db)
+      # Confirm first doc not updated, and result has no rev field
+      res = hd(resp.body)
+      assert res["id"] == "1" and res["error"] == "conflict"
+      assert Map.get(res, "rev") == nil
+      # Confirm other docs updated normally
+      assert revs_start_with(tl(resp.body), "2-")
+    end)
   end
 
   @tag :with_db
@@ -126,14 +130,16 @@ defmodule BulkDocsTest do
   end
 
   defp bulk_post(docs, db) do
-    resp = Couch.post("/#{db}/_bulk_docs", body: %{docs: docs})
+    retry_until(fn ->
+      resp = Couch.post("/#{db}/_bulk_docs", body: %{docs: docs})
 
-    assert resp.status_code == 201 and length(resp.body) == length(docs), """
-    Expected 201 and the same number of response rows as in request, but got
-    #{pretty_inspect(resp)}
-    """
+      assert resp.status_code == 201 and length(resp.body) == length(docs), """
+      Expected 201 and the same number of response rows as in request, but got
+      #{pretty_inspect(resp)}
+      """
 
-    resp
+      resp
+    end)
   end
 
   defp revs_start_with(rows, prefix) do
diff --git a/test/elixir/test/coffee_test.exs b/test/elixir/test/coffee_test.exs
index 82a0272..3b26f5e 100644
--- a/test/elixir/test/coffee_test.exs
+++ b/test/elixir/test/coffee_test.exs
@@ -53,9 +53,10 @@ defmodule CoffeeTest do
 
     assert resp.status_code === 201 and length(resp.body) === length(docs)
 
-    %{"rows" => values} = Couch.get("/#{db_name}/_design/coffee/_view/myview").body
-
-    assert 5 === hd(values)["value"]
+    retry_until(fn ->
+      %{"rows" => values} = Couch.get("/#{db_name}/_design/coffee/_view/myview").body
+      assert 5 === hd(values)["value"]
+    end)
 
     assert Couch.get("/#{db_name}/_design/coffee/_show/myshow/a").body === "Foo 100"
 
diff --git a/test/elixir/test/compact_test.exs b/test/elixir/test/compact_test.exs
index e60397f..4b0a5a0 100644
--- a/test/elixir/test/compact_test.exs
+++ b/test/elixir/test/compact_test.exs
@@ -12,6 +12,7 @@ defmodule CompactTest do
   @att_name "foo.txt"
   @att_plaintext "This is plain text"
 
+  @tag :skip_on_jenkins
   @tag :with_db
   test "compaction reduces size of deleted docs", context do
     db = context[:db_name]
diff --git a/test/elixir/test/lots_of_docs_test.exs b/test/elixir/test/lots_of_docs_test.exs
index 252de7a..4e25d43 100644
--- a/test/elixir/test/lots_of_docs_test.exs
+++ b/test/elixir/test/lots_of_docs_test.exs
@@ -53,6 +53,7 @@ defmodule LotsOfDocsTest do
     end)
   end
 
+  @tag :skip_on_jenkins
   @tag :with_db
   test "lots of docs with a regular view", context do
     db_name = context[:db_name]
@@ -70,17 +71,19 @@ defmodule LotsOfDocsTest do
       assert Map.fetch!(Enum.at(rows, i), "key") === i
     end)
 
-    %{"rows" => desc_rows, "total_rows" => desc_total_rows} =
-      query_view(db_name, "descending")
+    retry_until(fn ->
+      %{"rows" => desc_rows, "total_rows" => desc_total_rows} =
+        query_view(db_name, "descending")
 
-    assert desc_total_rows === Enum.count(desc_rows)
-    assert desc_total_rows === Enum.count(@docs_range)
+      assert desc_total_rows === Enum.count(desc_rows)
+      assert desc_total_rows === Enum.count(@docs_range)
 
-    @docs_range
-    |> Enum.reverse()
-    |> Enum.with_index()
-    |> Enum.each(fn {value, index} ->
-      assert Map.fetch!(Enum.at(desc_rows, index), "key") === value
+      @docs_range
+      |> Enum.reverse()
+      |> Enum.with_index()
+      |> Enum.each(fn {value, index} ->
+        assert Map.fetch!(Enum.at(desc_rows, index), "key") === value
+      end)
     end)
   end
 
diff --git a/test/elixir/test/partition_ddoc_test.exs b/test/elixir/test/partition_ddoc_test.exs
index ef1147f..85f66c4 100644
--- a/test/elixir/test/partition_ddoc_test.exs
+++ b/test/elixir/test/partition_ddoc_test.exs
@@ -156,6 +156,7 @@ defmodule PartitionDDocTest do
     assert %{"rows" => [%{"id" => "_design/foo"}]} = body
   end
 
+  @tag :skip_on_jenkins
   test "GET /dbname/_design_docs", context do
     db_name = context[:db_name]
 
diff --git a/test/elixir/test/partition_size_test.exs b/test/elixir/test/partition_size_test.exs
index c4d235b..68759ad 100644
--- a/test/elixir/test/partition_size_test.exs
+++ b/test/elixir/test/partition_size_test.exs
@@ -182,6 +182,7 @@ defmodule PartitionSizeTest do
     assert post_infos == pre_infos
   end
 
+  @tag :skip_on_jenkins
   test "get all partition sizes", context do
     db_name = context[:db_name]
     mk_docs(db_name)
diff --git a/test/elixir/test/partition_view_update_test.exs b/test/elixir/test/partition_view_update_test.exs
index 516943b..63c6268 100644
--- a/test/elixir/test/partition_view_update_test.exs
+++ b/test/elixir/test/partition_view_update_test.exs
@@ -29,6 +29,7 @@ defmodule PartitionViewUpdateTest do
     check_key.(2, 0)
   end
 
+  @tag :skip_on_jenkins
   @tag :with_partitioned_db
   test "query with update=false works", context do
     db_name = context[:db_name]
diff --git a/test/elixir/test/replication_test.exs b/test/elixir/test/replication_test.exs
index 9a20f78..e98775f 100644
--- a/test/elixir/test/replication_test.exs
+++ b/test/elixir/test/replication_test.exs
@@ -19,6 +19,8 @@ defmodule ReplicationTest do
   # happens for JavaScript tests.
   @moduletag config: [{"replicator", "startup_jitter", "0"}]
 
+  @moduletag :skip_on_jenkins
+
   test "source database does not exist" do
     name = random_db_name()
     check_not_found(name <> "_src", name <> "_tgt")
@@ -283,10 +285,14 @@ defmodule ReplicationTest do
     result = replicate(src_prefix <> src_db_name, tgt_prefix <> tgt_db_name)
     assert result["ok"]
 
-    src_info = get_db_info(src_db_name)
-    tgt_info = get_db_info(tgt_db_name)
+    src_info =
+      retry_until(fn ->
+        src_info = get_db_info(src_db_name)
+        tgt_info = get_db_info(tgt_db_name)
 
-    assert src_info["doc_count"] == tgt_info["doc_count"]
+        assert src_info["doc_count"] == tgt_info["doc_count"]
+        src_info
+      end)
 
     assert is_binary(result["session_id"])
     assert is_list(result["history"])
@@ -338,10 +344,12 @@ defmodule ReplicationTest do
     result = replicate(src_prefix <> src_db_name, tgt_prefix <> tgt_db_name)
     assert result["ok"]
 
-    src_info = get_db_info(src_db_name)
-    tgt_info = get_db_info(tgt_db_name)
+    retry_until(fn ->
+      src_info = get_db_info(src_db_name)
+      tgt_info = get_db_info(tgt_db_name)
 
-    assert tgt_info["doc_count"] == src_info["doc_count"]
+      assert tgt_info["doc_count"] == src_info["doc_count"]
+    end)
 
     assert is_binary(result["session_id"])
     assert is_list(result["history"])
@@ -400,12 +408,14 @@ defmodule ReplicationTest do
     result = replicate(src_prefix <> src_db_name, tgt_prefix <> tgt_db_name)
     assert result["ok"]
 
-    src_info = get_db_info(src_db_name)
-    tgt_info = get_db_info(tgt_db_name)
+    retry_until(fn ->
+      src_info = get_db_info(src_db_name)
+      tgt_info = get_db_info(tgt_db_name)
 
-    assert tgt_info["doc_count"] == src_info["doc_count"]
-    assert tgt_info["doc_del_count"] == src_info["doc_del_count"]
-    assert tgt_info["doc_del_count"] == 1
+      assert tgt_info["doc_count"] == src_info["doc_count"]
+      assert tgt_info["doc_del_count"] == src_info["doc_del_count"]
+      assert tgt_info["doc_del_count"] == 1
+    end)
 
     assert is_list(result["history"])
     assert length(result["history"]) == 3
@@ -701,14 +711,16 @@ defmodule ReplicationTest do
 
     replicate(repl_src, repl_tgt, body: %{:create_target => true})
 
-    src_info = get_db_info(src_db_name)
-    tgt_info = get_db_info(tgt_db_name)
+    retry_until(fn ->
+      src_info = get_db_info(src_db_name)
+      tgt_info = get_db_info(tgt_db_name)
 
-    assert tgt_info["doc_count"] == src_info["doc_count"]
+      assert tgt_info["doc_count"] == src_info["doc_count"]
 
-    src_shards = seq_to_shards(src_info["update_seq"])
-    tgt_shards = seq_to_shards(tgt_info["update_seq"])
-    assert tgt_shards == src_shards
+      src_shards = seq_to_shards(src_info["update_seq"])
+      tgt_shards = seq_to_shards(tgt_info["update_seq"])
+      assert tgt_shards == src_shards
+    end)
   end
 
   def run_filtered_repl(src_prefix, tgt_prefix) do
@@ -978,8 +990,11 @@ defmodule ReplicationTest do
     repl_src = src_prefix <> src_db_name
     repl_tgt = tgt_prefix <> tgt_db_name
 
-    create_db(src_db_name)
-    create_db(tgt_db_name)
+    retry_until(fn ->
+      create_db(src_db_name)
+      create_db(tgt_db_name)
+    end)
+
     delete_on_exit([src_db_name, tgt_db_name])
 
     docs = make_docs(1..10)
@@ -1043,8 +1058,10 @@ defmodule ReplicationTest do
       end
     end)
 
-    tgt_info = get_db_info(tgt_db_name)
-    assert tgt_info["doc_count"] == total_replicated
+    retry_until(fn ->
+      tgt_info = get_db_info(tgt_db_name)
+      assert tgt_info["doc_count"] == total_replicated
+    end)
 
     doc_ids_after = test_data[:after]
 
@@ -1098,10 +1115,12 @@ defmodule ReplicationTest do
       end
     end)
 
-    tgt_info = get_db_info(tgt_db_name)
+    retry_until(fn ->
+      tgt_info = get_db_info(tgt_db_name)
 
-    assert tgt_info["doc_count"] == total_replicated + total_replicated_after,
-           "#{inspect(test_data)}"
+      assert tgt_info["doc_count"] == total_replicated + total_replicated_after,
+             "#{inspect(test_data)}"
+    end)
 
     # Update a source document and re-replicate (no conflict introduced)
     conflict_id = test_data[:conflict_id]
@@ -1176,12 +1195,14 @@ defmodule ReplicationTest do
     assert result["docs_written"] == 1
     assert result["doc_write_failures"] == 0
 
-    copy = Couch.get!("/#{tgt_db_name}/#{conflict_id}", query: query).body
-    assert String.match?(copy["_rev"], ~r/^5-/)
-    assert is_list(copy["_conflicts"])
-    assert length(copy["_conflicts"]) == 1
-    conflict_rev = Enum.at(copy["_conflicts"], 0)
-    assert String.match?(conflict_rev, ~r/^5-/)
+    retry_until(fn ->
+      copy = Couch.get!("/#{tgt_db_name}/#{conflict_id}", query: query).body
+      assert String.match?(copy["_rev"], ~r/^5-/)
+      assert is_list(copy["_conflicts"])
+      assert length(copy["_conflicts"]) == 1
+      conflict_rev = Enum.at(copy["_conflicts"], 0)
+      assert String.match?(conflict_rev, ~r/^5-/)
+    end)
   end
 
   def run_continuous_repl(src_prefix, tgt_prefix) do
@@ -1646,9 +1667,11 @@ defmodule ReplicationTest do
         %{:w => 3}
       end
 
-    resp = Couch.put(uri, headers: headers, query: params, body: att[:body])
-    assert HTTPotion.Response.success?(resp)
-    Map.put(doc, "_rev", resp.body["rev"])
+    retry_until(fn ->
+      resp = Couch.put(uri, headers: headers, query: params, body: att[:body])
+      assert HTTPotion.Response.success?(resp)
+      Map.put(doc, "_rev", resp.body["rev"])
+    end)
   end
 
   def wait_for_repl(src_db_name, repl_id, expect_revs_checked) do
diff --git a/test/elixir/test/security_validation_test.exs b/test/elixir/test/security_validation_test.exs
index 56c4ec3..0df3a78 100644
--- a/test/elixir/test/security_validation_test.exs
+++ b/test/elixir/test/security_validation_test.exs
@@ -159,10 +159,12 @@ defmodule SecurityValidationTest do
     assert Couch.put("/#{db_name}/_security", body: sec_obj).body["ok"]
     assert Couch.post("/#{db_name}", body: @ddoc).body["ok"]
 
-    resp = Couch.put("/#{db_name}/test_doc", body: %{foo: 1}, headers: jerry)
-    assert resp.status_code == 403
-    assert resp.body["error"] == "forbidden"
-    assert resp.body["reason"] == "Documents must have an author field"
+    retry_until(fn ->
+      resp = Couch.put("/#{db_name}/test_doc", body: %{foo: 1}, headers: jerry)
+      assert resp.status_code == 403
+      assert resp.body["error"] == "forbidden"
+      assert resp.body["reason"] == "Documents must have an author field"
+    end)
 
     # Jerry can write the document
     assert Couch.put(
diff --git a/test/elixir/test/test_helper.exs b/test/elixir/test/test_helper.exs
index b2c3210..4df3bf7 100644
--- a/test/elixir/test/test_helper.exs
+++ b/test/elixir/test/test_helper.exs
@@ -1,5 +1,13 @@
+# If build number detected assume we running on Jenkins
+# and skip certain tests that fail on jenkins.
+exclude =
+  case System.get_env("BUILD_NUMBER") !== nil do
+    true -> [pending: true, skip_on_jenkins: true]
+    false -> [pending: true]
+  end
+
 ExUnit.configure(
-  exclude: [pending: true],
+  exclude: exclude,
   formatters: [JUnitFormatter, ExUnit.CLIFormatter]
 )
 
diff --git a/test/elixir/test/view_collation_test.exs b/test/elixir/test/view_collation_test.exs
index bf30031..7563ba4 100644
--- a/test/elixir/test/view_collation_test.exs
+++ b/test/elixir/test/view_collation_test.exs
@@ -70,28 +70,34 @@ defmodule ViewCollationTest do
   end
 
   test "ascending collation order", context do
-    resp = Couch.get(url(context))
-    pairs = Enum.zip(resp.body["rows"], @values)
+    retry_until(fn ->
+      resp = Couch.get(url(context))
+      pairs = Enum.zip(resp.body["rows"], @values)
 
-    Enum.each(pairs, fn {row, value} ->
-      assert row["key"] == convert(value)
+      Enum.each(pairs, fn {row, value} ->
+        assert row["key"] == convert(value)
+      end)
     end)
   end
 
   test "descending collation order", context do
-    resp = Couch.get(url(context), query: %{"descending" => "true"})
-    pairs = Enum.zip(resp.body["rows"], Enum.reverse(@values))
+    retry_until(fn ->
+      resp = Couch.get(url(context), query: %{"descending" => "true"})
+      pairs = Enum.zip(resp.body["rows"], Enum.reverse(@values))
 
-    Enum.each(pairs, fn {row, value} ->
-      assert row["key"] == convert(value)
+      Enum.each(pairs, fn {row, value} ->
+        assert row["key"] == convert(value)
+      end)
     end)
   end
 
   test "key query option", context do
     Enum.each(@values, fn value ->
-      resp = Couch.get(url(context), query: %{:key => :jiffy.encode(value)})
-      assert length(resp.body["rows"]) == 1
-      assert Enum.at(resp.body["rows"], 0)["key"] == convert(value)
+      retry_until(fn ->
+        resp = Couch.get(url(context), query: %{:key => :jiffy.encode(value)})
+        assert length(resp.body["rows"]) == 1
+        assert Enum.at(resp.body["rows"], 0)["key"] == convert(value)
+      end)
     end)
   end