diff options
author | Garren Smith <garren.smith@gmail.com> | 2019-02-27 15:55:25 +0200 |
---|---|---|
committer | Garren Smith <garren.smith@gmail.com> | 2019-03-05 10:36:37 +0200 |
commit | 36e129b77f4774c73c5e20b59156ceccdbe234cd (patch) | |
tree | e05b3993ee678cad88e58a176f81112fde8c1f4d | |
parent | 5e4234d1229ce032554c53634601f148b51ade66 (diff) | |
download | couchdb-36e129b77f4774c73c5e20b59156ceccdbe234cd.tar.gz |
Convert Attachment.js to Elixir
-rw-r--r-- | test/elixir/test/attachments.exs | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/test/elixir/test/attachments.exs b/test/elixir/test/attachments.exs new file mode 100644 index 000000000..cae006962 --- /dev/null +++ b/test/elixir/test/attachments.exs @@ -0,0 +1,470 @@ +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) + 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) + 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) + 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) + 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}, + 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) + assert resp.status_code in [201, 202] + rev = resp.body["rev"] + + resp = Couch.delete("/#{db_name}/bin_doc/foo.txt") + + assert resp.status_code == 409 + + resp = Couch.delete("/#{db_name}/bin_doc/foo.txt", query: %{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"] + ) + + 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) + assert resp.status_code == 409 + + # non-existent rev + resp = + Couch.put( + "/#{db_name}/bin_doc3/attachment.txt", + query: %{rev: "1-adae8575ecea588919bd08eb020c708e"}, + 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}, + 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}) + 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"] + ) + + 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}, + 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, + 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"] + ) + + 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"] + ) + + 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}, + 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}, + 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"] + ) + + 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 + ) + + 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}, + 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] + ) + + 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 + ) + + 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, + 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 |