diff options
author | garren smith <garren.smith@gmail.com> | 2019-03-05 14:58:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-05 14:58:42 +0200 |
commit | d8eec700086af0a601755d86100bb772dc1ee88e (patch) | |
tree | 14ed0b8233c0f570390a3386359b9d3e52b3e2d1 | |
parent | 92c004b73d5262f5cb8097999401fd3cdf35da64 (diff) | |
download | couchdb-d8eec700086af0a601755d86100bb772dc1ee88e.tar.gz |
Jenkins add attachment test (#1953)
* update readme for all tests written
* Convert Attachment.js to Elixir
* add w:3
* add more w:3
* more w:3
* mix format
-rw-r--r-- | test/elixir/README.md | 12 | ||||
-rw-r--r-- | test/elixir/test/attachments.exs | 482 |
2 files changed, 488 insertions, 6 deletions
diff --git a/test/elixir/README.md b/test/elixir/README.md index 8300fa101..883afb512 100644 --- a/test/elixir/README.md +++ b/test/elixir/README.md @@ -33,13 +33,13 @@ X means done, - means partially - [ ] Port attachment_views.js - [ ] Port auth_cache.js - [X] Port basics.js - - [ ] Port batch_save.js - - [ ] Port bulk_docs.js + - [X] Port batch_save.js + - [X] Port bulk_docs.js - [X] Port changes.js - [X] Port coffee.js - - [ ] Port compact.js + - [X] Port compact.js - [X] Port config.js - - [ ] Port conflicts.js + - [X] Port conflicts.js - [ ] Port cookie_auth.js - [ ] Port copy_doc.js - [X] Port delayed_commits.js @@ -68,7 +68,7 @@ X means done, - means partially - [ ] Port reduce_false.js - [ ] Port reduce_false_temp.js - [X] Port reduce.js - - [-] Port replication.js + - [X] Port replication.js - [ ] Port replicator_db_bad_rep_id.js - [ ] Port replicator_db_by_doc_id.js - [ ] Port replicator_db_compact_rep_db.js @@ -90,7 +90,7 @@ X means done, - means partially - [ ] Port rev_stemming.js - [X] Port rewrite.js - [ ] Port rewrite_js.js - - [ ] Port security_validation.js + - [X] Port security_validation.js - [ ] Port show_documents.js - [ ] Port stats.js - [ ] Port update_documents.js diff --git a/test/elixir/test/attachments.exs b/test/elixir/test/attachments.exs new file mode 100644 index 000000000..7f235213e --- /dev/null +++ b/test/elixir/test/attachments.exs @@ -0,0 +1,482 @@ +defmodule AttachmentsTest do + use CouchTestCase + + @moduletag :attachments + + # MD5 Digests of compressible attachments and therefore Etags + # will vary depending on platform gzip implementation. + # These MIME types are defined in [attachments] compressible_types + @bin_att_doc %{ + _id: "bin_doc", + _attachments: %{ + "foo.txt": %{ + content_type: "application/octet-stream", + data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=" + } + } + } + + @moduledoc """ + Test CouchDB attachments + This is a port of the attachments.js suite + """ + + @tag :with_db + test "saves attachment successfully", context do + db_name = context[:db_name] + + resp = Couch.put("/#{db_name}/bin_doc", body: @bin_att_doc, query: %{w: 3}) + assert resp.status_code in [201, 202] + assert resp.body["ok"] + end + + @tag :with_db + test "errors for bad attachment", context do + db_name = context[:db_name] + + bad_att_doc = %{ + _id: "bad_doc", + _attachments: %{ + "foo.txt": %{ + content_type: "text/plain", + data: "notBase64Encoded=" + } + } + } + + resp = Couch.put("/#{db_name}/bad_doc", body: bad_att_doc, query: %{w: 3}) + assert resp.status_code == 400 + end + + @tag :with_db + test "reads attachment successfully", context do + db_name = context[:db_name] + + resp = Couch.put("/#{db_name}/bin_doc", body: @bin_att_doc, query: %{w: 3}) + assert resp.status_code in [201, 202] + + resp = Couch.get("/#{db_name}/bin_doc/foo.txt", body: @bin_att_doc) + + assert resp.body == "This is a base64 encoded text" + assert resp.headers["Content-Type"] == "application/octet-stream" + assert resp.headers["Etag"] == "\"aEI7pOYCRBLTRQvvqYrrJQ==\"" + end + + @tag :with_db + test "update attachment", context do + db_name = context[:db_name] + + bin_att_doc2 = %{ + _id: "bin_doc2", + _attachments: %{ + "foo.txt": %{ + content_type: "text/plain", + data: "" + } + } + } + + resp = Couch.put("/#{db_name}/bin_doc2", body: bin_att_doc2, query: %{w: 3}) + assert resp.status_code in [201, 202] + rev = resp.body["rev"] + + resp = Couch.get("/#{db_name}/bin_doc2/foo.txt") + + assert resp.headers["Content-Type"] == "text/plain" + assert resp.body == "" + + resp = + Couch.put( + "/#{db_name}/bin_doc2/foo2.txt", + query: %{rev: rev, w: 3}, + body: "This is no base64 encoded text", + headers: ["Content-Type": "text/plain;charset=utf-8"] + ) + + assert resp.status_code in [201, 202] + assert Regex.match?(~r/bin_doc2\/foo2.txt/, resp.headers["location"]) + end + + @tag :with_db + test "delete attachment", context do + db_name = context[:db_name] + + resp = Couch.put("/#{db_name}/bin_doc", body: @bin_att_doc, query: %{w: 3}) + assert resp.status_code in [201, 202] + rev = resp.body["rev"] + + resp = Couch.delete("/#{db_name}/bin_doc/foo.txt", query: %{w: 3}) + + assert resp.status_code == 409 + + resp = Couch.delete("/#{db_name}/bin_doc/foo.txt", query: %{w: 3, rev: rev}) + assert resp.status_code == 200 + assert resp.headers["location"] == nil + end + + @tag :with_db + test "saves binary", context do + db_name = context[:db_name] + + bin_data = "JHAPDO*AU£PN ){(3u[d 93DQ9¡€])} ææøo'∂ƒæ≤çæππ•¥∫¶®#†π¶®¥π€ª®˙π8np" + + resp = + Couch.put( + "/#{db_name}/bin_doc3/attachment.txt", + body: bin_data, + headers: ["Content-Type": "text/plain;charset=utf-8"], + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + rev = resp.body["rev"] + + resp = Couch.get("/#{db_name}/bin_doc3/attachment.txt") + assert resp.body == bin_data + + resp = + Couch.put("/#{db_name}/bin_doc3/attachment.txt", body: bin_data, query: %{w: 3}) + + assert resp.status_code == 409 + + # non-existent rev + resp = + Couch.put( + "/#{db_name}/bin_doc3/attachment.txt", + query: %{rev: "1-adae8575ecea588919bd08eb020c708e", w: 3}, + headers: ["Content-Type": "text/plain;charset=utf-8"], + body: bin_data + ) + + assert resp.status_code == 409 + + # current rev + resp = + Couch.put( + "/#{db_name}/bin_doc3/attachment.txt", + query: %{rev: rev, w: 3}, + headers: ["Content-Type": "text/plain;charset=utf-8"], + body: bin_data + ) + + assert resp.status_code == 201 + + rev = resp.body["rev"] + + resp = Couch.get("/#{db_name}/bin_doc3/attachment.txt") + assert String.downcase(resp.headers["Content-Type"]) == "text/plain;charset=utf-8" + assert resp.body == bin_data + + resp = Couch.get("/#{db_name}/bin_doc3/attachment.txt", query: %{rev: rev}) + assert String.downcase(resp.headers["Content-Type"]) == "text/plain;charset=utf-8" + assert resp.body == bin_data + + resp = Couch.delete("/#{db_name}/bin_doc3/attachment.txt", query: %{rev: rev, w: 3}) + assert resp.status_code == 200 + + resp = Couch.get("/#{db_name}/bin_doc3/attachment.txt") + assert resp.status_code == 404 + + resp = Couch.get("/#{db_name}/bin_doc3/attachment.txt", query: %{rev: rev}) + assert String.downcase(resp.headers["Content-Type"]) == "text/plain;charset=utf-8" + assert resp.body == bin_data + end + + @tag :with_db + test "empty attachments", context do + db_name = context[:db_name] + + resp = + Couch.put( + "/#{db_name}/bin_doc4/attachment.txt", + body: "", + headers: ["Content-Type": "text/plain;charset=utf-8"], + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + rev = resp.body["rev"] + + resp = Couch.get("/#{db_name}/bin_doc4/attachment.txt") + assert resp.status_code == 200 + assert resp.body == "" + + resp = + Couch.put( + "/#{db_name}/bin_doc4/attachment.txt", + query: %{rev: rev, w: 3}, + headers: ["Content-Type": "text/plain;charset=utf-8"], + body: "This is a string" + ) + + assert resp.status_code == 201 + + resp = Couch.get("/#{db_name}/bin_doc4/attachment.txt") + assert resp.status_code == 200 + assert resp.body == "This is a string" + end + + @tag :with_db + test "large attachments COUCHDB-366", context do + db_name = context[:db_name] + + lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + range = 1..10 + + large_att = Enum.reduce(range, lorem, fn _, acc -> lorem <> acc end) + + resp = + Couch.put( + "/#{db_name}/bin_doc5/attachment.txt", + body: large_att, + query: %{w: 3}, + headers: ["Content-Type": "text/plain;charset=utf-8"] + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + resp = Couch.get("/#{db_name}/bin_doc5/attachment.txt") + assert String.downcase(resp.headers["Content-Type"]) == "text/plain;charset=utf-8" + assert resp.body == large_att + + lorem_b64 = + "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4g" + + range = 1..10 + + large_b64_att = Enum.reduce(range, lorem_b64, fn _, acc -> lorem_b64 <> acc end) + + resp = + Couch.get( + "/#{db_name}/bin_doc5", + query: %{attachments: true}, + headers: [Accept: "application/json"] + ) + + assert large_b64_att == resp.body["_attachments"]["attachment.txt"]["data"] + end + + @tag :with_db + test "etags for attachments", context do + db_name = context[:db_name] + + lorem_att = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + resp = + Couch.put( + "/#{db_name}/bin_doc6/attachment.txt", + body: lorem_att, + headers: ["Content-Type": "text/plain;charset=utf-8"], + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + resp = Couch.get("/#{db_name}/bin_doc6/attachment.txt") + assert resp.status_code == 200 + etag = resp.headers["etag"] + + resp = + Couch.get("/#{db_name}/bin_doc6/attachment.txt", headers: ["if-none-match": etag]) + + assert resp.status_code == 304 + end + + @tag :with_db + test "test COUCHDB-497 - empty attachments", context do + db_name = context[:db_name] + + lorem_att = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + resp = + Couch.put( + "/#{db_name}/bin_doc7/attachment.txt", + body: lorem_att, + headers: ["Content-Type": "text/plain;charset=utf-8"], + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + rev = resp.body["rev"] + + resp = + Couch.put( + "/#{db_name}/bin_doc7/empty.txt", + query: %{rev: rev, w: 3}, + body: "", + headers: ["Content-Type": "text/plain;charset=utf-8"] + ) + + assert resp.status_code == 201 + rev = resp.body["rev"] + + resp = + Couch.put( + "/#{db_name}/bin_doc7/empty.txt", + query: %{rev: rev, w: 3}, + body: "", + headers: ["Content-Type": "text/plain;charset=utf-8"] + ) + + assert resp.status_code == 201 + end + + @tag :with_db + test "implicit doc creation allows creating docs with a reserved id. COUCHDB-565", + context do + db_name = context[:db_name] + + resp = + Couch.put( + "/#{db_name}/_nonexistant/attachment.txt", + body: "ATTACHMENT INFO", + headers: ["Content-Type": "text/plain;charset=utf-8"], + query: %{w: 3} + ) + + assert resp.status_code == 400 + end + + @tag :with_db + test "COUCHDB-809 - stubs should only require the 'stub' field", context do + db_name = context[:db_name] + + stub_doc = %{ + _id: "stub_doc", + _attachments: %{ + "foo.txt": %{ + content_type: "text/plain", + data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=" + } + } + } + + resp = + Couch.put( + "/#{db_name}/stub_doc", + body: stub_doc, + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + rev = resp.body["rev"] + + stub_doc = + Map.merge(stub_doc, %{ + _rev: rev, + _attachments: %{"foo.txt": %{stub: true}} + }) + + resp = + Couch.put( + "/#{db_name}/stub_doc", + query: %{rev: rev, w: 3}, + body: stub_doc + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + rev = resp.body["rev"] + + stub_doc = + Map.merge(stub_doc, %{ + _rev: rev, + _attachments: %{"foo.txt": %{stub: true, revpos: 10}} + }) + + resp = + Couch.put( + "/#{db_name}/stub_doc", + query: %{rev: rev}, + body: stub_doc + ) + + assert resp.status_code == 412 + assert resp.body["error"] == "missing_stub" + end + + @tag :with_db + test "md5 header for attachments", context do + db_name = context[:db_name] + md5 = "MntvB0NYESObxH4VRDUycw==" + + bin_data = "foo bar" + + resp = + Couch.put( + "/#{db_name}/bin_doc8/attachment.txt", + body: bin_data, + headers: ["Content-Type": "application/octet-stream", "Content-MD5": md5], + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + resp = Couch.get("/#{db_name}/bin_doc8/attachment.txt") + assert resp.status_code == 200 + assert md5 == resp.headers["Content-MD5"] + end + + @tag :with_db + test "attachment via multipart/form-data", context do + db_name = context[:db_name] + + form_data_doc = %{ + _id: "form-data-doc" + } + + resp = + Couch.put( + "/#{db_name}/form_data_doc", + body: form_data_doc, + query: %{w: 3} + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + rev = resp.body["rev"] + + body = + "------TF\r\n" <> + "Content-Disposition: form-data; name=\"_rev\"\r\n\r\n" <> + rev <> + "\r\n" <> + "------TF\r\n" <> + "Content-Disposition: form-data; name=\"_attachments\"; filename=\"file.txt\"\r\n" <> + "Content-Type: text/plain\r\n\r\n" <> + "contents of file.txt\r\n\r\n" <> "------TF--" + + resp = + Couch.post( + "/#{db_name}/form_data_doc", + body: body, + query: %{w: 3}, + headers: [ + Referer: "http://127.0.0.1:15984", + "Content-Type": "multipart/form-data; boundary=----TF", + "Content-Length": byte_size(body) + ] + ) + + assert resp.status_code in [201, 202] + assert resp.body["ok"] + + resp = Couch.get("/#{db_name}/form_data_doc") + assert resp.status_code == 200 + + doc = resp.body + assert doc["_attachments"]["file.txt"]["length"] == 22 + end +end |