summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Shorin <kxepal@apache.org>2014-06-03 01:51:46 +0400
committerAlexander Shorin <kxepal@apache.org>2015-12-02 03:49:05 +0300
commit3a91b3a9250abb474ac7c690225bda233c83659e (patch)
tree6020de03ca7d2257253fac306adffc1cd095f05a
parentdd01551b9d2b042f7beac525fc32a499e4194bcf (diff)
downloadcouchdb-3a91b3a9250abb474ac7c690225bda233c83659e.tar.gz
Port 140-attachments-comp.t etap test suite to eunit
- Merge into couchdb_attachments_tests suite; - Add PUT requests to test_request util; - Remove dependency from files outside fixtures directory; - Group test cases to reduce amount of duplicate code; - Fix hidden issue with gzip encoding: for encoding_length stub info check using zlib:gzip on 2KiB+ files leads to mismatch by 2-4 bytes and this difference grows with file size. Using gzip fun code from couch_stream solves the issue.
-rw-r--r--license.skip1
-rw-r--r--test/couchdb/Makefile.am3
-rw-r--r--test/couchdb/couchdb_attachments_tests.erl380
-rw-r--r--test/couchdb/fixtures/logo.pngbin0 -> 3010 bytes
-rw-r--r--test/couchdb/test_request.erl9
-rwxr-xr-xtest/etap/140-attachment-comp.t728
-rw-r--r--test/etap/Makefile.am1
7 files changed, 388 insertions, 734 deletions
diff --git a/license.skip b/license.skip
index aab5fc256..3050026ce 100644
--- a/license.skip
+++ b/license.skip
@@ -166,6 +166,7 @@
^test/Makefile.in
^test/couchdb/Makefile
^test/couchdb/Makefile.in
+^test/couchdb/fixtures/logo.png
^test/etap/.*.beam
^test/etap/.*.o
^test/etap/.deps/.*
diff --git a/test/couchdb/Makefile.am b/test/couchdb/Makefile.am
index 540583b5f..9a4dda5bb 100644
--- a/test/couchdb/Makefile.am
+++ b/test/couchdb/Makefile.am
@@ -48,7 +48,8 @@ fixture_files = \
fixtures/couch_config_tests_1.ini \
fixtures/couch_config_tests_2.ini \
fixtures/couch_stats_aggregates.cfg \
- fixtures/couch_stats_aggregates.ini
+ fixtures/couch_stats_aggregates.ini \
+ fixtures/logo.png
EXTRA_DIST = \
run.in \
diff --git a/test/couchdb/couchdb_attachments_tests.erl b/test/couchdb/couchdb_attachments_tests.erl
index aef187324..cf597855b 100644
--- a/test/couchdb/couchdb_attachments_tests.erl
+++ b/test/couchdb/couchdb_attachments_tests.erl
@@ -15,13 +15,23 @@
-include("couch_eunit.hrl").
-include_lib("couchdb/couch_db.hrl").
+-define(COMPRESSION_LEVEL, 8).
+-define(ATT_BIN_NAME, <<"logo.png">>).
+-define(ATT_TXT_NAME, <<"file.erl">>).
+-define(FIXTURE_PNG, filename:join([?FIXTURESDIR, "logo.png"])).
+-define(FIXTURE_TXT, ?FILE).
-define(TIMEOUT, 1000).
+-define(TIMEOUT_EUNIT, 10).
-define(TIMEWAIT, 100).
-define(i2l(I), integer_to_list(I)).
start() ->
{ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+ % ensure in default compression settings for attachments_compression_tests
+ couch_config:set("attachments", "compression_level",
+ ?i2l(?COMPRESSION_LEVEL), false),
+ couch_config:set("attachments", "compressible_types", "text/*", false),
Pid.
stop(Pid) ->
@@ -43,7 +53,35 @@ setup() ->
Host = Addr ++ ":" ++ ?i2l(Port),
{Host, ?b2l(DbName)}.
+setup({binary, standalone}) ->
+ {Host, DbName} = setup(),
+ setup_att(fun create_standalone_png_att/2, Host, DbName, ?FIXTURE_PNG);
+setup({text, standalone}) ->
+ {Host, DbName} = setup(),
+ setup_att(fun create_standalone_text_att/2, Host, DbName, ?FIXTURE_TXT);
+setup({binary, inline}) ->
+ {Host, DbName} = setup(),
+ setup_att(fun create_inline_png_att/2, Host, DbName, ?FIXTURE_PNG);
+setup({text, inline}) ->
+ {Host, DbName} = setup(),
+ setup_att(fun create_inline_text_att/2, Host, DbName, ?FIXTURE_TXT);
+setup(compressed) ->
+ {Host, DbName} = setup(),
+ setup_att(fun create_already_compressed_att/2, Host, DbName, ?FIXTURE_TXT).
+setup_att(Fun, Host, DbName, File) ->
+ HttpHost = "http://" ++ Host,
+ AttUrl = Fun(HttpHost, DbName),
+ {ok, Data} = file:read_file(File),
+ DocUrl = string:join([HttpHost, DbName, "doc"], "/"),
+ Helpers = {DbName, DocUrl, AttUrl},
+ {Data, Helpers}.
+
+teardown(_, {_, {DbName, _, _}}) ->
+ teardown(DbName).
+
teardown({_, DbName}) ->
+ teardown(DbName);
+teardown(DbName) ->
ok = couch_server:delete(?l2b(DbName), []),
ok.
@@ -55,7 +93,8 @@ attachments_test_() ->
setup,
fun start/0, fun stop/1,
[
- attachments_md5_tests()
+ attachments_md5_tests(),
+ attachments_compression_tests()
]
}
}.
@@ -79,6 +118,67 @@ attachments_md5_tests() ->
}
}.
+attachments_compression_tests() ->
+ Funs = [
+ fun should_get_att_without_accept_gzip_encoding/2,
+ fun should_get_att_with_accept_gzip_encoding/2,
+ fun should_get_att_with_accept_deflate_encoding/2,
+ fun should_return_406_response_on_unsupported_encoding/2,
+ fun should_get_doc_with_att_data/2,
+ fun should_get_doc_with_att_data_stub/2
+ ],
+ {
+ "Attachments compression tests",
+ [
+ {
+ "Created via Attachments API",
+ created_attachments_compression_tests(standalone, Funs)
+ },
+ {
+ "Created inline via Document API",
+ created_attachments_compression_tests(inline, Funs)
+ },
+ {
+ "Created already been compressed via Attachments API",
+ {
+ foreachx,
+ fun setup/1, fun teardown/2,
+ [{compressed, Fun} || Fun <- Funs]
+ }
+ },
+ {
+ foreach,
+ fun setup/0, fun teardown/1,
+ [
+ fun should_not_create_compressed_att_with_deflate_encoding/1,
+ fun should_not_create_compressed_att_with_compress_encoding/1,
+ fun should_create_compressible_att_with_ctype_params/1
+ ]
+ }
+ ]
+ }.
+
+created_attachments_compression_tests(Mod, Funs) ->
+ [
+ {
+ "Compressiable attachments",
+ {
+ foreachx,
+ fun setup/1, fun teardown/2,
+ [{{text, Mod}, Fun} || Fun <- Funs]
+ }
+ },
+ {
+ "Uncompressiable attachments",
+ {
+ foreachx,
+ fun setup/1, fun teardown/2,
+ [{{binary, Mod}, Fun} || Fun <- Funs]
+ }
+ }
+ ].
+
+
should_upload_attachment_without_md5({Host, DbName}) ->
?_test(begin
@@ -212,10 +312,218 @@ should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
],
{ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
?assertEqual(400, Code),
- ?assertEqual(<<"content_md5_mismatch">>,
- get_json(Json, [<<"error">>]))
+ ?assertEqual(<<"content_md5_mismatch">>, get_json(Json, [<<"error">>]))
+ end).
+
+should_get_att_without_accept_gzip_encoding(_, {Data, {_, _, AttUrl}}) ->
+ ?_test(begin
+ {ok, Code, Headers, Body} = test_request:get(AttUrl),
+ ?assertEqual(200, Code),
+ ?assertNot(lists:member({"Content-Encoding", "gzip"}, Headers)),
+ ?assertEqual(Data, iolist_to_binary(Body))
+ end).
+
+should_get_att_with_accept_gzip_encoding(compressed, {Data, {_, _, AttUrl}}) ->
+ ?_test(begin
+ {ok, Code, Headers, Body} = test_request:get(
+ AttUrl, [{"Accept-Encoding", "gzip"}]),
+ ?assertEqual(200, Code),
+ ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+ ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+ end);
+should_get_att_with_accept_gzip_encoding({text, _}, {Data, {_, _, AttUrl}}) ->
+ ?_test(begin
+ {ok, Code, Headers, Body} = test_request:get(
+ AttUrl, [{"Accept-Encoding", "gzip"}]),
+ ?assertEqual(200, Code),
+ ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+ ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+ end);
+should_get_att_with_accept_gzip_encoding({binary, _}, {Data, {_, _, AttUrl}}) ->
+ ?_test(begin
+ {ok, Code, Headers, Body} = test_request:get(
+ AttUrl, [{"Accept-Encoding", "gzip"}]),
+ ?assertEqual(200, Code),
+ ?assertEqual(undefined,
+ couch_util:get_value("Content-Encoding", Headers)),
+ ?assertEqual(Data, iolist_to_binary(Body))
+ end).
+
+should_get_att_with_accept_deflate_encoding(_, {Data, {_, _, AttUrl}}) ->
+ ?_test(begin
+ {ok, Code, Headers, Body} = test_request:get(
+ AttUrl, [{"Accept-Encoding", "deflate"}]),
+ ?assertEqual(200, Code),
+ ?assertEqual(undefined,
+ couch_util:get_value("Content-Encoding", Headers)),
+ ?assertEqual(Data, iolist_to_binary(Body))
+ end).
+
+should_return_406_response_on_unsupported_encoding(_, {_, {_, _, AttUrl}}) ->
+ ?_assertEqual(406,
+ begin
+ {ok, Code, _, _} = test_request:get(
+ AttUrl, [{"Accept-Encoding", "deflate, *;q=0"}]),
+ Code
+ end).
+
+should_get_doc_with_att_data(compressed, {Data, {_, DocUrl, _}}) ->
+ ?_test(begin
+ Url = DocUrl ++ "?attachments=true",
+ {ok, Code, _, Body} = test_request:get(
+ Url, [{"Accept", "application/json"}]),
+ ?assertEqual(200, Code),
+ Json = ejson:decode(Body),
+ AttJson = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+ AttData = couch_util:get_nested_json_value(
+ AttJson, [<<"data">>]),
+ ?assertEqual(
+ <<"text/plain">>,
+ couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+ ?assertEqual(Data, base64:decode(AttData))
+ end);
+should_get_doc_with_att_data({text, _}, {Data, {_, DocUrl, _}}) ->
+ ?_test(begin
+ Url = DocUrl ++ "?attachments=true",
+ {ok, Code, _, Body} = test_request:get(
+ Url, [{"Accept", "application/json"}]),
+ ?assertEqual(200, Code),
+ Json = ejson:decode(Body),
+ AttJson = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+ AttData = couch_util:get_nested_json_value(
+ AttJson, [<<"data">>]),
+ ?assertEqual(
+ <<"text/plain">>,
+ couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+ ?assertEqual(Data, base64:decode(AttData))
+ end);
+should_get_doc_with_att_data({binary, _}, {Data, {_, DocUrl, _}}) ->
+ ?_test(begin
+ Url = DocUrl ++ "?attachments=true",
+ {ok, Code, _, Body} = test_request:get(
+ Url, [{"Accept", "application/json"}]),
+ ?assertEqual(200, Code),
+ Json = ejson:decode(Body),
+ AttJson = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+ AttData = couch_util:get_nested_json_value(
+ AttJson, [<<"data">>]),
+ ?assertEqual(
+ <<"image/png">>,
+ couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+ ?assertEqual(Data, base64:decode(AttData))
+ end).
+
+should_get_doc_with_att_data_stub(compressed, {Data, {_, DocUrl, _}}) ->
+ ?_test(begin
+ Url = DocUrl ++ "?att_encoding_info=true",
+ {ok, Code, _, Body} = test_request:get(
+ Url, [{"Accept", "application/json"}]),
+ ?assertEqual(200, Code),
+ Json = ejson:decode(Body),
+ {AttJson} = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+ ?assertEqual(<<"gzip">>,
+ couch_util:get_value(<<"encoding">>, AttJson)),
+ AttLength = couch_util:get_value(<<"length">>, AttJson),
+ EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
+ ?assertEqual(AttLength, EncLength),
+ ?assertEqual(iolist_size(zlib:gzip(Data)), AttLength)
+ end);
+should_get_doc_with_att_data_stub({text, _}, {Data, {_, DocUrl, _}}) ->
+ ?_test(begin
+ Url = DocUrl ++ "?att_encoding_info=true",
+ {ok, Code, _, Body} = test_request:get(
+ Url, [{"Accept", "application/json"}]),
+ ?assertEqual(200, Code),
+ Json = ejson:decode(Body),
+ {AttJson} = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+ ?assertEqual(<<"gzip">>,
+ couch_util:get_value(<<"encoding">>, AttJson)),
+ AttEncLength = iolist_size(gzip(Data)),
+ ?assertEqual(AttEncLength,
+ couch_util:get_value(<<"encoded_length">>, AttJson)),
+ ?assertEqual(byte_size(Data),
+ couch_util:get_value(<<"length">>, AttJson))
+ end);
+should_get_doc_with_att_data_stub({binary, _}, {Data, {_, DocUrl, _}}) ->
+ ?_test(begin
+ Url = DocUrl ++ "?att_encoding_info=true",
+ {ok, Code, _, Body} = test_request:get(
+ Url, [{"Accept", "application/json"}]),
+ ?assertEqual(200, Code),
+ Json = ejson:decode(Body),
+ {AttJson} = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+ ?assertEqual(undefined,
+ couch_util:get_value(<<"encoding">>, AttJson)),
+ ?assertEqual(undefined,
+ couch_util:get_value(<<"encoded_length">>, AttJson)),
+ ?assertEqual(byte_size(Data),
+ couch_util:get_value(<<"length">>, AttJson))
end).
+should_not_create_compressed_att_with_deflate_encoding({Host, DbName}) ->
+ ?_assertEqual(415,
+ begin
+ HttpHost = "http://" ++ Host,
+ AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+ {ok, Data} = file:read_file(?FIXTURE_TXT),
+ Body = zlib:compress(Data),
+ Headers = [
+ {"Content-Encoding", "deflate"},
+ {"Content-Type", "text/plain"}
+ ],
+ {ok, Code, _, _} = test_request:put(AttUrl, Headers, Body),
+ Code
+ end).
+
+should_not_create_compressed_att_with_compress_encoding({Host, DbName}) ->
+ % Note: As of OTP R13B04, it seems there's no LZW compression
+ % (i.e. UNIX compress utility implementation) lib in OTP.
+ % However there's a simple working Erlang implementation at:
+ % http://scienceblogs.com/goodmath/2008/01/simple_lempelziv_compression_i.php
+ ?_assertEqual(415,
+ begin
+ HttpHost = "http://" ++ Host,
+ AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+ {ok, Data} = file:read_file(?FIXTURE_TXT),
+ Headers = [
+ {"Content-Encoding", "compress"},
+ {"Content-Type", "text/plain"}
+ ],
+ {ok, Code, _, _} = test_request:put(AttUrl, Headers, Data),
+ Code
+ end).
+
+should_create_compressible_att_with_ctype_params({Host, DbName}) ->
+ {timeout, ?TIMEOUT_EUNIT, ?_test(begin
+ HttpHost = "http://" ++ Host,
+ DocUrl = string:join([HttpHost, DbName, ?docid()], "/"),
+ AttUrl = string:join([DocUrl, ?b2l(?ATT_TXT_NAME)], "/"),
+ {ok, Data} = file:read_file(?FIXTURE_TXT),
+ Headers = [{"Content-Type", "text/plain; charset=UTF-8"}],
+ {ok, Code0, _, _} = test_request:put(AttUrl, Headers, Data),
+ ?assertEqual(201, Code0),
+
+ {ok, Code1, _, Body} = test_request:get(
+ DocUrl ++ "?att_encoding_info=true"),
+ ?assertEqual(200, Code1),
+ Json = ejson:decode(Body),
+ {AttJson} = couch_util:get_nested_json_value(
+ Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+ ?assertEqual(<<"gzip">>,
+ couch_util:get_value(<<"encoding">>, AttJson)),
+ AttEncLength = iolist_size(gzip(Data)),
+ ?assertEqual(AttEncLength,
+ couch_util:get_value(<<"encoded_length">>, AttJson)),
+ ?assertEqual(byte_size(Data),
+ couch_util:get_value(<<"length">>, AttJson))
+ end)}.
+
get_json(Json, Path) ->
couch_util:get_nested_json_value(Json, Path).
@@ -262,3 +570,69 @@ request(Method, Url, Headers, Body) ->
erlang:decode_packet(http, Header, []),
Json = ejson:decode(Body1),
{ok, Code, Json}.
+
+create_standalone_text_att(Host, DbName) ->
+ {ok, Data} = file:read_file(?FIXTURE_TXT),
+ Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+ {ok, Code, _Headers, _Body} = test_request:put(
+ Url, [{"Content-Type", "text/plain"}], Data),
+ ?assertEqual(201, Code),
+ Url.
+
+create_standalone_png_att(Host, DbName) ->
+ {ok, Data} = file:read_file(?FIXTURE_PNG),
+ Url = string:join([Host, DbName, "doc", ?b2l(?ATT_BIN_NAME)], "/"),
+ {ok, Code, _Headers, _Body} = test_request:put(
+ Url, [{"Content-Type", "image/png"}], Data),
+ ?assertEqual(201, Code),
+ Url.
+
+create_inline_text_att(Host, DbName) ->
+ {ok, Data} = file:read_file(?FIXTURE_TXT),
+ Url = string:join([Host, DbName, "doc"], "/"),
+ Doc = {[
+ {<<"_attachments">>, {[
+ {?ATT_TXT_NAME, {[
+ {<<"content_type">>, <<"text/plain">>},
+ {<<"data">>, base64:encode(Data)}
+ ]}
+ }]}}
+ ]},
+ {ok, Code, _Headers, _Body} = test_request:put(
+ Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+ ?assertEqual(201, Code),
+ string:join([Url, ?b2l(?ATT_TXT_NAME)], "/").
+
+create_inline_png_att(Host, DbName) ->
+ {ok, Data} = file:read_file(?FIXTURE_PNG),
+ Url = string:join([Host, DbName, "doc"], "/"),
+ Doc = {[
+ {<<"_attachments">>, {[
+ {?ATT_BIN_NAME, {[
+ {<<"content_type">>, <<"image/png">>},
+ {<<"data">>, base64:encode(Data)}
+ ]}
+ }]}}
+ ]},
+ {ok, Code, _Headers, _Body} = test_request:put(
+ Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+ ?assertEqual(201, Code),
+ string:join([Url, ?b2l(?ATT_BIN_NAME)], "/").
+
+create_already_compressed_att(Host, DbName) ->
+ {ok, Data} = file:read_file(?FIXTURE_TXT),
+ Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+ {ok, Code, _Headers, _Body} = test_request:put(
+ Url, [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
+ zlib:gzip(Data)),
+ ?assertEqual(201, Code),
+ Url.
+
+gzip(Data) ->
+ Z = zlib:open(),
+ ok = zlib:deflateInit(Z, ?COMPRESSION_LEVEL, deflated, 16 + 15, 8, default),
+ zlib:deflate(Z, Data),
+ Last = zlib:deflate(Z, [], finish),
+ ok = zlib:deflateEnd(Z),
+ ok = zlib:close(Z),
+ Last.
diff --git a/test/couchdb/fixtures/logo.png b/test/couchdb/fixtures/logo.png
new file mode 100644
index 000000000..d21ac025b
--- /dev/null
+++ b/test/couchdb/fixtures/logo.png
Binary files differ
diff --git a/test/couchdb/test_request.erl b/test/couchdb/test_request.erl
index 7abb92f3a..d6725ea06 100644
--- a/test/couchdb/test_request.erl
+++ b/test/couchdb/test_request.erl
@@ -12,7 +12,7 @@
-module(test_request).
--export([get/1, get/2]).
+-export([get/1, get/2, put/2, put/3]).
-export([request/3, request/4]).
get(Url) ->
@@ -22,6 +22,13 @@ get(Url, Headers) ->
request(get, Url, Headers).
+put(Url, Body) ->
+ request(put, Url, [], Body).
+
+put(Url, Headers, Body) ->
+ request(put, Url, Headers, Body).
+
+
request(Method, Url, Headers) ->
request(Method, Url, Headers, []).
diff --git a/test/etap/140-attachment-comp.t b/test/etap/140-attachment-comp.t
deleted file mode 100755
index 6f075ce44..000000000
--- a/test/etap/140-attachment-comp.t
+++ /dev/null
@@ -1,728 +0,0 @@
-#!/usr/bin/env escript
-%% -*- erlang -*-
-
-% 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.
-
-test_db_name() ->
- <<"couch_test_atts_compression">>.
-
-main(_) ->
- test_util:init_code_path(),
-
- etap:plan(85),
- case (catch test()) of
- ok ->
- etap:end_tests();
- Other ->
- etap:diag(io_lib:format("Test died abnormally: ~p", [Other])),
- etap:bail(Other)
- end,
- ok.
-
-test() ->
- couch_server_sup:start_link(test_util:config_files()),
- put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")),
- put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))),
- timer:sleep(1000),
- couch_server:delete(test_db_name(), []),
- couch_db:create(test_db_name(), []),
-
- couch_config:set("attachments", "compression_level", "8", false),
- couch_config:set("attachments", "compressible_types", "text/*", false),
-
- create_1st_text_att(),
- create_1st_png_att(),
- create_2nd_text_att(),
- create_2nd_png_att(),
-
- tests_for_1st_text_att(),
- tests_for_1st_png_att(),
- tests_for_2nd_text_att(),
- tests_for_2nd_png_att(),
-
- create_already_compressed_att(db_url() ++ "/doc_comp_att", "readme.txt"),
- test_already_compressed_att(db_url() ++ "/doc_comp_att", "readme.txt"),
-
- test_create_already_compressed_att_with_invalid_content_encoding(
- db_url() ++ "/doc_att_deflate",
- "readme.txt",
- zlib:compress(test_text_data()),
- "deflate"
- ),
-
- % COUCHDB-1711 - avoid weird timng/scheduling/request handling issue
- timer:sleep(100),
-
- test_create_already_compressed_att_with_invalid_content_encoding(
- db_url() ++ "/doc_att_compress",
- "readme.txt",
- % Note: As of OTP R13B04, it seems there's no LZW compression
- % (i.e. UNIX compress utility implementation) lib in OTP.
- % However there's a simple working Erlang implementation at:
- % http://scienceblogs.com/goodmath/2008/01/simple_lempelziv_compression_i.php
- test_text_data(),
- "compress"
- ),
-
- test_compressible_type_with_parameters(),
-
- timer:sleep(3000), % to avoid mochiweb socket closed exceptions
- couch_server:delete(test_db_name(), []),
- couch_server_sup:stop(),
- ok.
-
-db_url() ->
- "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/" ++
- binary_to_list(test_db_name()).
-
-create_1st_text_att() ->
- {ok, Code, _Headers, _Body} = test_util:request(
- db_url() ++ "/testdoc1/readme.txt",
- [{"Content-Type", "text/plain"}],
- put,
- test_text_data()),
- etap:is(Code, 201, "Created text attachment using the standalone api"),
- ok.
-
-create_1st_png_att() ->
- {ok, Code, _Headers, _Body} = test_util:request(
- db_url() ++ "/testdoc2/icon.png",
- [{"Content-Type", "image/png"}],
- put,
- test_png_data()),
- etap:is(Code, 201, "Created png attachment using the standalone api"),
- ok.
-
-% create a text attachment using the non-standalone attachment api
-create_2nd_text_att() ->
- DocJson = {[
- {<<"_attachments">>, {[
- {<<"readme.txt">>, {[
- {<<"content_type">>, <<"text/plain">>},
- {<<"data">>, base64:encode(test_text_data())}
- ]}
- }]}}
- ]},
- {ok, Code, _Headers, _Body} = test_util:request(
- db_url() ++ "/testdoc3",
- [{"Content-Type", "application/json"}],
- put,
- ejson:encode(DocJson)),
- etap:is(Code, 201, "Created text attachment using the non-standalone api"),
- ok.
-
-% create a png attachment using the non-standalone attachment api
-create_2nd_png_att() ->
- DocJson = {[
- {<<"_attachments">>, {[
- {<<"icon.png">>, {[
- {<<"content_type">>, <<"image/png">>},
- {<<"data">>, base64:encode(test_png_data())}
- ]}
- }]}}
- ]},
- {ok, Code, _Headers, _Body} = test_util:request(
- db_url() ++ "/testdoc4",
- [{"Content-Type", "application/json"}],
- put,
- ejson:encode(DocJson)),
- etap:is(Code, 201, "Created png attachment using the non-standalone api"),
- ok.
-
-create_already_compressed_att(DocUri, AttName) ->
- {ok, Code, _Headers, _Body} = test_util:request(
- DocUri ++ "/" ++ AttName,
- [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
- put,
- zlib:gzip(test_text_data())),
- etap:is(
- Code,
- 201,
- "Created already compressed attachment using the standalone api"
- ),
- ok.
-
-tests_for_1st_text_att() ->
- test_get_1st_text_att_with_accept_encoding_gzip(),
- test_get_1st_text_att_without_accept_encoding_header(),
- test_get_1st_text_att_with_accept_encoding_deflate(),
- test_get_1st_text_att_with_accept_encoding_deflate_only(),
- test_get_doc_with_1st_text_att(),
- test_1st_text_att_stub().
-
-tests_for_1st_png_att() ->
- test_get_1st_png_att_without_accept_encoding_header(),
- test_get_1st_png_att_with_accept_encoding_gzip(),
- test_get_1st_png_att_with_accept_encoding_deflate(),
- test_get_doc_with_1st_png_att(),
- test_1st_png_att_stub().
-
-tests_for_2nd_text_att() ->
- test_get_2nd_text_att_with_accept_encoding_gzip(),
- test_get_2nd_text_att_without_accept_encoding_header(),
- test_get_doc_with_2nd_text_att(),
- test_2nd_text_att_stub().
-
-tests_for_2nd_png_att() ->
- test_get_2nd_png_att_without_accept_encoding_header(),
- test_get_2nd_png_att_with_accept_encoding_gzip(),
- test_get_doc_with_2nd_png_att(),
- test_2nd_png_att_stub().
-
-test_get_1st_text_att_with_accept_encoding_gzip() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc1/readme.txt",
- [{"Accept-Encoding", "gzip"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, true, "received body is gziped"),
- Uncompressed = zlib:gunzip(iolist_to_binary(Body)),
- etap:is(
- Uncompressed,
- test_text_data(),
- "received data for the 1st text attachment is ok"
- ),
- ok.
-
-test_get_1st_text_att_without_accept_encoding_header() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc1/readme.txt",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, false, "received body is not gziped"),
- etap:is(
- iolist_to_binary(Body),
- test_text_data(),
- "received data for the 1st text attachment is ok"
- ),
- ok.
-
-test_get_1st_text_att_with_accept_encoding_deflate() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc1/readme.txt",
- [{"Accept-Encoding", "deflate"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, false, "received body is not gziped"),
- Deflated = lists:member({"Content-Encoding", "deflate"}, Headers),
- etap:is(Deflated, false, "received body is not deflated"),
- etap:is(
- iolist_to_binary(Body),
- test_text_data(),
- "received data for the 1st text attachment is ok"
- ),
- ok.
-
-test_get_1st_text_att_with_accept_encoding_deflate_only() ->
- {ok, Code, _Headers, _Body} = test_util:request(
- db_url() ++ "/testdoc1/readme.txt",
- [{"Accept-Encoding", "deflate, *;q=0"}],
- get),
- etap:is(
- Code,
- 406,
- "HTTP response code is 406 for an unsupported content encoding request"
- ),
- ok.
-
-test_get_1st_png_att_without_accept_encoding_header() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc2/icon.png",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Encoding = couch_util:get_value("Content-Encoding", Headers),
- etap:is(Encoding, undefined, "received body is not gziped"),
- etap:is(
- iolist_to_binary(Body),
- test_png_data(),
- "received data for the 1st png attachment is ok"
- ),
- ok.
-
-test_get_1st_png_att_with_accept_encoding_gzip() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc2/icon.png",
- [{"Accept-Encoding", "gzip"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Encoding = couch_util:get_value("Content-Encoding", Headers),
- etap:is(Encoding, undefined, "received body is not gziped"),
- etap:is(
- iolist_to_binary(Body),
- test_png_data(),
- "received data for the 1st png attachment is ok"
- ),
- ok.
-
-test_get_1st_png_att_with_accept_encoding_deflate() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc2/icon.png",
- [{"Accept-Encoding", "deflate"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Encoding = couch_util:get_value("Content-Encoding", Headers),
- etap:is(Encoding, undefined, "received body is in identity form"),
- etap:is(
- iolist_to_binary(Body),
- test_png_data(),
- "received data for the 1st png attachment is ok"
- ),
- ok.
-
-test_get_doc_with_1st_text_att() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc1?attachments=true",
- [{"Accept", "application/json"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- TextAttJson = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"readme.txt">>]
- ),
- TextAttType = couch_util:get_nested_json_value(
- TextAttJson,
- [<<"content_type">>]
- ),
- TextAttData = couch_util:get_nested_json_value(
- TextAttJson,
- [<<"data">>]
- ),
- etap:is(
- TextAttType,
- <<"text/plain">>,
- "1st text attachment has type text/plain"
- ),
- %% check the attachment's data is the base64 encoding of the plain text
- %% and not the base64 encoding of the gziped plain text
- etap:is(
- TextAttData,
- base64:encode(test_text_data()),
- "1st text attachment data is properly base64 encoded"
- ),
- ok.
-
-test_1st_text_att_stub() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc1?att_encoding_info=true",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- {TextAttJson} = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"readme.txt">>]
- ),
- TextAttLength = couch_util:get_value(<<"length">>, TextAttJson),
- etap:is(
- TextAttLength,
- byte_size(test_text_data()),
- "1st text attachment stub length matches the uncompressed length"
- ),
- TextAttEncoding = couch_util:get_value(<<"encoding">>, TextAttJson),
- etap:is(
- TextAttEncoding,
- <<"gzip">>,
- "1st text attachment stub has the encoding field set to gzip"
- ),
- TextAttEncLength = couch_util:get_value(<<"encoded_length">>, TextAttJson),
- etap:is(
- TextAttEncLength,
- iolist_size(zlib:gzip(test_text_data())),
- "1st text attachment stub encoded_length matches the compressed length"
- ),
- ok.
-
-test_get_doc_with_1st_png_att() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc2?attachments=true",
- [{"Accept", "application/json"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- PngAttJson = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"icon.png">>]
- ),
- PngAttType = couch_util:get_nested_json_value(
- PngAttJson,
- [<<"content_type">>]
- ),
- PngAttData = couch_util:get_nested_json_value(
- PngAttJson,
- [<<"data">>]
- ),
- etap:is(PngAttType, <<"image/png">>, "attachment has type image/png"),
- etap:is(
- PngAttData,
- base64:encode(test_png_data()),
- "1st png attachment data is properly base64 encoded"
- ),
- ok.
-
-test_1st_png_att_stub() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc2?att_encoding_info=true",
- [{"Accept", "application/json"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- {PngAttJson} = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"icon.png">>]
- ),
- PngAttLength = couch_util:get_value(<<"length">>, PngAttJson),
- etap:is(
- PngAttLength,
- byte_size(test_png_data()),
- "1st png attachment stub length matches the uncompressed length"
- ),
- PngEncoding = couch_util:get_value(<<"encoding">>, PngAttJson),
- etap:is(
- PngEncoding,
- undefined,
- "1st png attachment stub doesn't have an encoding field"
- ),
- PngEncLength = couch_util:get_value(<<"encoded_length">>, PngAttJson),
- etap:is(
- PngEncLength,
- undefined,
- "1st png attachment stub doesn't have an encoded_length field"
- ),
- ok.
-
-test_get_2nd_text_att_with_accept_encoding_gzip() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc3/readme.txt",
- [{"Accept-Encoding", "gzip"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, true, "received body is gziped"),
- Uncompressed = zlib:gunzip(iolist_to_binary(Body)),
- etap:is(
- Uncompressed,
- test_text_data(),
- "received data for the 2nd text attachment is ok"
- ),
- ok.
-
-test_get_2nd_text_att_without_accept_encoding_header() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc3/readme.txt",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, false, "received body is not gziped"),
- etap:is(
- Body,
- test_text_data(),
- "received data for the 2nd text attachment is ok"
- ),
- ok.
-
-test_get_2nd_png_att_without_accept_encoding_header() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc4/icon.png",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, false, "received body is not gziped"),
- etap:is(
- Body,
- test_png_data(),
- "received data for the 2nd png attachment is ok"
- ),
- ok.
-
-test_get_2nd_png_att_with_accept_encoding_gzip() ->
- {ok, Code, Headers, Body} = test_util:request(
- db_url() ++ "/testdoc4/icon.png",
- [{"Accept-Encoding", "gzip"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, false, "received body is not gziped"),
- etap:is(
- Body,
- test_png_data(),
- "received data for the 2nd png attachment is ok"
- ),
- ok.
-
-test_get_doc_with_2nd_text_att() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc3?attachments=true",
- [{"Accept", "application/json"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- TextAttJson = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"readme.txt">>]
- ),
- TextAttType = couch_util:get_nested_json_value(
- TextAttJson,
- [<<"content_type">>]
- ),
- TextAttData = couch_util:get_nested_json_value(
- TextAttJson,
- [<<"data">>]
- ),
- etap:is(TextAttType, <<"text/plain">>, "attachment has type text/plain"),
- %% check the attachment's data is the base64 encoding of the plain text
- %% and not the base64 encoding of the gziped plain text
- etap:is(
- TextAttData,
- base64:encode(test_text_data()),
- "2nd text attachment data is properly base64 encoded"
- ),
- ok.
-
-test_2nd_text_att_stub() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc3?att_encoding_info=true",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- {TextAttJson} = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"readme.txt">>]
- ),
- TextAttLength = couch_util:get_value(<<"length">>, TextAttJson),
- etap:is(
- TextAttLength,
- byte_size(test_text_data()),
- "2nd text attachment stub length matches the uncompressed length"
- ),
- TextAttEncoding = couch_util:get_value(<<"encoding">>, TextAttJson),
- etap:is(
- TextAttEncoding,
- <<"gzip">>,
- "2nd text attachment stub has the encoding field set to gzip"
- ),
- TextAttEncLength = couch_util:get_value(<<"encoded_length">>, TextAttJson),
- etap:is(
- TextAttEncLength,
- iolist_size(zlib:gzip(test_text_data())),
- "2nd text attachment stub encoded_length matches the compressed length"
- ),
- ok.
-
-test_get_doc_with_2nd_png_att() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc4?attachments=true",
- [{"Accept", "application/json"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- PngAttJson = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"icon.png">>]
- ),
- PngAttType = couch_util:get_nested_json_value(
- PngAttJson,
- [<<"content_type">>]
- ),
- PngAttData = couch_util:get_nested_json_value(
- PngAttJson,
- [<<"data">>]
- ),
- etap:is(PngAttType, <<"image/png">>, "attachment has type image/png"),
- etap:is(
- PngAttData,
- base64:encode(test_png_data()),
- "2nd png attachment data is properly base64 encoded"
- ),
- ok.
-
-test_2nd_png_att_stub() ->
- {ok, Code, _Headers, Body} = test_util:request(
- db_url() ++ "/testdoc4?att_encoding_info=true",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- {PngAttJson} = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"icon.png">>]
- ),
- PngAttLength = couch_util:get_value(<<"length">>, PngAttJson),
- etap:is(
- PngAttLength,
- byte_size(test_png_data()),
- "2nd png attachment stub length matches the uncompressed length"
- ),
- PngEncoding = couch_util:get_value(<<"encoding">>, PngAttJson),
- etap:is(
- PngEncoding,
- undefined,
- "2nd png attachment stub doesn't have an encoding field"
- ),
- PngEncLength = couch_util:get_value(<<"encoded_length">>, PngAttJson),
- etap:is(
- PngEncLength,
- undefined,
- "2nd png attachment stub doesn't have an encoded_length field"
- ),
- ok.
-
-test_already_compressed_att(DocUri, AttName) ->
- test_get_already_compressed_att_with_accept_gzip(DocUri, AttName),
- test_get_already_compressed_att_without_accept(DocUri, AttName),
- test_get_already_compressed_att_stub(DocUri, AttName).
-
-test_get_already_compressed_att_with_accept_gzip(DocUri, AttName) ->
- {ok, Code, Headers, Body} = test_util:request(
- DocUri ++ "/" ++ AttName,
- [{"Accept-Encoding", "gzip"}],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, true, "received body is gziped"),
- etap:is(
- Body,
- zlib:gzip(test_text_data()),
- "received data for the already compressed attachment is ok"
- ),
- ok.
-
-test_get_already_compressed_att_without_accept(DocUri, AttName) ->
- {ok, Code, Headers, Body} = test_util:request(
- DocUri ++ "/" ++ AttName,
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers),
- etap:is(Gziped, false, "received body is not gziped"),
- etap:is(
- Body,
- test_text_data(),
- "received data for the already compressed attachment is ok"
- ),
- ok.
-
-test_get_already_compressed_att_stub(DocUri, AttName) ->
- {ok, Code, _Headers, Body} = test_util:request(
- DocUri ++ "?att_encoding_info=true",
- [],
- get),
- etap:is(Code, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body),
- {AttJson} = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, iolist_to_binary(AttName)]
- ),
- AttLength = couch_util:get_value(<<"length">>, AttJson),
- etap:is(
- AttLength,
- iolist_size((zlib:gzip(test_text_data()))),
- "Already compressed attachment stub length matches the "
- "compressed length"
- ),
- Encoding = couch_util:get_value(<<"encoding">>, AttJson),
- etap:is(
- Encoding,
- <<"gzip">>,
- "Already compressed attachment stub has the encoding field set to gzip"
- ),
- EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
- etap:is(
- EncLength,
- AttLength,
- "Already compressed attachment stub encoded_length matches the "
- "length field value"
- ),
- ok.
-
-test_create_already_compressed_att_with_invalid_content_encoding(
- DocUri, AttName, AttData, Encoding) ->
- {ok, Code, _Headers, _Body} = test_util:request(
- DocUri ++ "/" ++ AttName,
- [{"Content-Encoding", Encoding}, {"Content-Type", "text/plain"}],
- put,
- AttData),
- etap:is(
- Code,
- 415,
- "Couldn't create an already compressed attachment using the "
- "unsupported encoding '" ++ Encoding ++ "'"
- ),
- ok.
-
-test_compressible_type_with_parameters() ->
- {ok, Code, _Headers, _Body} = test_util:request(
- db_url() ++ "/testdoc5/readme.txt",
- [{"Content-Type", "text/plain; charset=UTF-8"}],
- put,
- test_text_data()),
- etap:is(Code, 201, "Created text attachment with MIME type "
- "'text/plain; charset=UTF-8' using the standalone api"),
- {ok, Code2, Headers2, Body} = test_util:request(
- db_url() ++ "/testdoc5/readme.txt",
- [{"Accept-Encoding", "gzip"}],
- get),
- etap:is(Code2, 200, "HTTP response code is 200"),
- Gziped = lists:member({"Content-Encoding", "gzip"}, Headers2),
- etap:is(Gziped, true, "received body is gziped"),
- Uncompressed = zlib:gunzip(iolist_to_binary(Body)),
- etap:is(Uncompressed, test_text_data(), "received data is gzipped"),
- {ok, Code3, _Headers3, Body3} = test_util:request(
- db_url() ++ "/testdoc5?att_encoding_info=true",
- [],
- get),
- etap:is(Code3, 200, "HTTP response code is 200"),
- Json = ejson:decode(Body3),
- {TextAttJson} = couch_util:get_nested_json_value(
- Json,
- [<<"_attachments">>, <<"readme.txt">>]
- ),
- TextAttLength = couch_util:get_value(<<"length">>, TextAttJson),
- etap:is(
- TextAttLength,
- byte_size(test_text_data()),
- "text attachment stub length matches the uncompressed length"
- ),
- TextAttEncoding = couch_util:get_value(<<"encoding">>, TextAttJson),
- etap:is(
- TextAttEncoding,
- <<"gzip">>,
- "text attachment stub has the encoding field set to gzip"
- ),
- TextAttEncLength = couch_util:get_value(<<"encoded_length">>, TextAttJson),
- etap:is(
- TextAttEncLength,
- iolist_size(zlib:gzip(test_text_data())),
- "text attachment stub encoded_length matches the compressed length"
- ),
- ok.
-
-test_png_data() ->
- {ok, Data} = file:read_file(
- test_util:source_file("share/www/image/logo.png")
- ),
- Data.
-
-test_text_data() ->
- {ok, Data} = file:read_file(
- test_util:source_file("README.rst")
- ),
- Data.
diff --git a/test/etap/Makefile.am b/test/etap/Makefile.am
index f54e927e0..94ff6f2f7 100644
--- a/test/etap/Makefile.am
+++ b/test/etap/Makefile.am
@@ -36,7 +36,6 @@ fixture_files = \
fixtures/test.couch
tap_files = \
- 140-attachment-comp.t \
150-invalid-view-seq.t \
160-vhosts.t \
170-os-daemons.es \