1defmodule CompactTest do
2  use CouchTestCase
3
4  @moduletag :compact
5
6  @moduledoc """
7  Test CouchDB compaction
8  This is a port of compact.js
9  """
10
11  @att_doc_id "att_doc"
12  @att_name "foo.txt"
13  @att_plaintext "This is plain text"
14
15  # Need to investigate why compaction is not compacting (or compactor cannot complete)
16  # Refer:- https://github.com/apache/couchdb/pull/2127
17  @tag :pending
18  @tag :skip_on_jenkins
19  @tag :with_db
20  test "compaction reduces size of deleted docs", context do
21    db = context[:db_name]
22    docs = populate(db)
23    info = get_info(db)
24    orig_data_size = info["sizes"]["active"]
25    orig_disk_size = info["sizes"]["file"]
26    start_time = info["instance_start_time"]
27    assert is_integer(orig_data_size) and is_integer(orig_disk_size)
28    assert orig_data_size < orig_disk_size
29
30    delete(db, docs)
31
32    retry_until(fn ->
33      deleted_data_size = get_info(db)["data_size"]
34      assert deleted_data_size > orig_data_size
35    end)
36
37    deleted_data_size = get_info(db)["data_size"]
38
39    compact(db)
40
41    retry_until(fn ->
42      assert get_info(db)["instance_start_time"] == start_time
43      assert_attachment_available(db)
44      info = get_info(db)
45      final_data_size = info["sizes"]["active"]
46      final_disk_size = info["sizes"]["file"]
47      assert final_data_size < final_disk_size
48      assert is_integer(final_data_size) and is_integer(final_disk_size)
49      assert final_data_size < deleted_data_size
50    end)
51  end
52
53  defp assert_attachment_available(db) do
54    resp = Couch.get("/#{db}/#{@att_doc_id}/#{@att_name}")
55    assert resp.body == @att_plaintext
56    assert resp.headers["content-type"] == "text/plain"
57    assert Couch.get("/#{db}").body["doc_count"] == 1
58  end
59
60  defp populate(db) do
61    docs = create_docs(0..19)
62    resp = Couch.post("/#{db}/_bulk_docs", body: %{docs: docs})
63    assert resp.status_code in [201, 202]
64    docs = rev(docs, resp.body)
65
66    doc = %{
67      _id: "#{@att_doc_id}",
68      _attachments: %{
69        "#{@att_name}": %{content_type: "text/plain", data: Base.encode64(@att_plaintext)}
70      }
71    }
72
73    resp = Couch.put("/#{db}/#{doc._id}", body: doc)
74    assert resp.status_code in [201, 202]
75    docs
76  end
77
78  defp delete(db, docs) do
79    docs = Enum.map(docs, &Map.put(&1, :_deleted, true))
80    resp = Couch.post("/#{db}/_bulk_docs", body: %{docs: docs})
81    assert resp.status_code in [201, 202]
82    assert Couch.post("/#{db}/_ensure_full_commit").body["ok"] == true
83  end
84
85  defp get_info(db) do
86    Couch.get("/#{db}").body
87  end
88end
89