diff options
| author | Michael Klishin <michael@clojurewerkz.org> | 2020-03-30 23:10:31 +0300 |
|---|---|---|
| committer | Michael Klishin <michael@clojurewerkz.org> | 2020-03-30 23:10:31 +0300 |
| commit | d0b904178aef106f9d71ee40c7747fad03d15021 (patch) | |
| tree | 7d4a6775a62c2f9345fad34cb29c3a0cf29bc734 | |
| parent | 518f6c9bf95449dca38c068e541be95d15949224 (diff) | |
| download | rabbitmq-server-git-d0b904178aef106f9d71ee40c7747fad03d15021.tar.gz | |
Continue splitting unit_*_SUITE suites
| -rw-r--r-- | test/unit_SUITE.erl | 965 | ||||
| -rw-r--r-- | test/unit_amqp091_content_framing_SUITE.erl | 240 | ||||
| -rw-r--r-- | test/unit_collections_SUITE.erl | 60 | ||||
| -rw-r--r-- | test/unit_config_value_encryption_SUITE.erl | 242 | ||||
| -rw-r--r-- | test/unit_config_value_encryption_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app (renamed from test/unit_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app) | 0 | ||||
| -rw-r--r-- | test/unit_config_value_encryption_SUITE_data/rabbit_shovel_test.passphrase (renamed from test/unit_SUITE_data/rabbit_shovel_test.passphrase) | 0 | ||||
| -rw-r--r-- | test/unit_disk_monitor_SUITE.erl | 61 | ||||
| -rw-r--r-- | test/unit_disk_monitor_mocks_SUITE.erl | 121 | ||||
| -rw-r--r-- | test/unit_gen_server2_SUITE.erl | 79 | ||||
| -rw-r--r-- | test/unit_inbroker_parallel_SUITE.erl | 13 | ||||
| -rw-r--r-- | test/unit_operator_policy_SUITE.erl | 122 | ||||
| -rw-r--r-- | test/unit_plugin_directories_SUITE.erl | 85 | ||||
| -rw-r--r-- | test/unit_supervisor2_SUITE.erl | 78 |
13 files changed, 1032 insertions, 1034 deletions
diff --git a/test/unit_SUITE.erl b/test/unit_SUITE.erl deleted file mode 100644 index 2d697c6fd6..0000000000 --- a/test/unit_SUITE.erl +++ /dev/null @@ -1,965 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% https://www.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. -%% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. -%% - --module(unit_SUITE). - --include_lib("common_test/include/ct.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("rabbit_common/include/rabbit.hrl"). --include_lib("rabbit_common/include/rabbit_framing.hrl"). - --compile(export_all). - -all() -> - [ - {group, parallel_tests}, - {group, sequential_tests} - ]. - -groups() -> - [ - {parallel_tests, [parallel], [ - {access_control, [parallel], [ - auth_backend_internal_expand_topic_permission - ]}, - {basic_header_handling, [parallel], [ - write_table_with_invalid_existing_type, - invalid_existing_headers, - disparate_invalid_header_entries_accumulate_separately, - corrupt_or_invalid_headers_are_overwritten, - invalid_same_header_entry_accumulation - ]}, - content_framing, - content_transcoding, - rabbitmqctl_encode, - pmerge, - plmerge, - merge_operator_policy_definitions, - rabbit_direct_extract_extra_auth_props, - {supervisor2, [], [ - check_shutdown_stop, - check_shutdown_ignored - ]}, - table_codec, - unfold - ]}, - {sequential_tests, [], [ - decrypt_start_app, - decrypt_start_app_file, - decrypt_start_app_undefined, - decrypt_start_app_wrong_passphrase, - decrypt_config, - listing_plugins_from_multiple_directories - ]} - ]. - -init_per_group(_, Config) -> Config. -end_per_group(_, Config) -> Config. - -init_per_testcase(TC, Config) when TC =:= decrypt_start_app; - TC =:= decrypt_start_app_file; - TC =:= decrypt_start_app_undefined; - TC =:= decrypt_start_app_wrong_passphrase -> - application:set_env(rabbit, feature_flags_file, "", [{persistent, true}]), - Config; -init_per_testcase(_Testcase, Config) -> - Config. - -end_per_testcase(_TC, _Config) -> - ok. - -%% ------------------------------------------------------------------- -%% basic_header_handling. -%% ------------------------------------------------------------------- --define(XDEATH_TABLE, - [{<<"reason">>, longstr, <<"blah">>}, - {<<"queue">>, longstr, <<"foo.bar.baz">>}, - {<<"exchange">>, longstr, <<"my-exchange">>}, - {<<"routing-keys">>, array, []}]). - --define(ROUTE_TABLE, [{<<"redelivered">>, bool, <<"true">>}]). - --define(BAD_HEADER(K), {<<K>>, longstr, <<"bad ", K>>}). --define(BAD_HEADER2(K, Suf), {<<K>>, longstr, <<"bad ", K, Suf>>}). --define(FOUND_BAD_HEADER(K), {<<K>>, array, [{longstr, <<"bad ", K>>}]}). - -write_table_with_invalid_existing_type(_Config) -> - prepend_check(<<"header1">>, ?XDEATH_TABLE, [?BAD_HEADER("header1")]). - -invalid_existing_headers(_Config) -> - Headers = - prepend_check(<<"header2">>, ?ROUTE_TABLE, [?BAD_HEADER("header2")]), - {array, [{table, ?ROUTE_TABLE}]} = - rabbit_misc:table_lookup(Headers, <<"header2">>), - passed. - -disparate_invalid_header_entries_accumulate_separately(_Config) -> - BadHeaders = [?BAD_HEADER("header2")], - Headers = prepend_check(<<"header2">>, ?ROUTE_TABLE, BadHeaders), - Headers2 = prepend_check(<<"header1">>, ?XDEATH_TABLE, - [?BAD_HEADER("header1") | Headers]), - {table, [?FOUND_BAD_HEADER("header1"), - ?FOUND_BAD_HEADER("header2")]} = - rabbit_misc:table_lookup(Headers2, ?INVALID_HEADERS_KEY), - passed. - -corrupt_or_invalid_headers_are_overwritten(_Config) -> - Headers0 = [?BAD_HEADER("header1"), - ?BAD_HEADER("x-invalid-headers")], - Headers1 = prepend_check(<<"header1">>, ?XDEATH_TABLE, Headers0), - {table,[?FOUND_BAD_HEADER("header1"), - ?FOUND_BAD_HEADER("x-invalid-headers")]} = - rabbit_misc:table_lookup(Headers1, ?INVALID_HEADERS_KEY), - passed. - -invalid_same_header_entry_accumulation(_Config) -> - BadHeader1 = ?BAD_HEADER2("header1", "a"), - Headers = prepend_check(<<"header1">>, ?ROUTE_TABLE, [BadHeader1]), - Headers2 = prepend_check(<<"header1">>, ?ROUTE_TABLE, - [?BAD_HEADER2("header1", "b") | Headers]), - {table, InvalidHeaders} = - rabbit_misc:table_lookup(Headers2, ?INVALID_HEADERS_KEY), - {array, [{longstr,<<"bad header1b">>}, - {longstr,<<"bad header1a">>}]} = - rabbit_misc:table_lookup(InvalidHeaders, <<"header1">>), - passed. - -prepend_check(HeaderKey, HeaderTable, Headers) -> - Headers1 = rabbit_basic:prepend_table_header( - HeaderKey, HeaderTable, Headers), - {table, Invalid} = - rabbit_misc:table_lookup(Headers1, ?INVALID_HEADERS_KEY), - {Type, Value} = rabbit_misc:table_lookup(Headers, HeaderKey), - {array, [{Type, Value} | _]} = - rabbit_misc:table_lookup(Invalid, HeaderKey), - Headers1. - -decrypt_config(_Config) -> - %% Take all available block ciphers. - Hashes = rabbit_pbe:supported_hashes(), - Ciphers = rabbit_pbe:supported_ciphers(), - Iterations = [1, 10, 100, 1000], - %% Loop through all hashes, ciphers and iterations. - _ = [begin - PassPhrase = crypto:strong_rand_bytes(16), - do_decrypt_config({C, H, I, PassPhrase}) - end || H <- Hashes, C <- Ciphers, I <- Iterations], - ok. - -do_decrypt_config(Algo = {C, H, I, P}) -> - ok = application:load(rabbit), - RabbitConfig = application:get_all_env(rabbit), - %% Encrypt a few values in configuration. - %% Common cases. - _ = [encrypt_value(Key, Algo) || Key <- [ - tcp_listeners, - num_tcp_acceptors, - ssl_options, - vm_memory_high_watermark, - default_pass, - default_permissions, - cluster_nodes, - auth_mechanisms, - msg_store_credit_disc_bound]], - %% Special case: encrypt a value in a list. - {ok, [LoopbackUser]} = application:get_env(rabbit, loopback_users), - EncLoopbackUser = rabbit_pbe:encrypt_term(C, H, I, P, LoopbackUser), - application:set_env(rabbit, loopback_users, [{encrypted, EncLoopbackUser}]), - %% Special case: encrypt a value in a key/value list. - {ok, TCPOpts} = application:get_env(rabbit, tcp_listen_options), - {_, Backlog} = lists:keyfind(backlog, 1, TCPOpts), - {_, Linger} = lists:keyfind(linger, 1, TCPOpts), - EncBacklog = rabbit_pbe:encrypt_term(C, H, I, P, Backlog), - EncLinger = rabbit_pbe:encrypt_term(C, H, I, P, Linger), - TCPOpts1 = lists:keyreplace(backlog, 1, TCPOpts, {backlog, {encrypted, EncBacklog}}), - TCPOpts2 = lists:keyreplace(linger, 1, TCPOpts1, {linger, {encrypted, EncLinger}}), - application:set_env(rabbit, tcp_listen_options, TCPOpts2), - %% Decrypt configuration. - rabbit_prelaunch_conf:decrypt_config([rabbit], Algo), - %% Check that configuration was decrypted properly. - RabbitConfig = application:get_all_env(rabbit), - ok = application:unload(rabbit), - ok. - -encrypt_value(Key, {C, H, I, P}) -> - {ok, Value} = application:get_env(rabbit, Key), - EncValue = rabbit_pbe:encrypt_term(C, H, I, P, Value), - application:set_env(rabbit, Key, {encrypted, EncValue}). - -decrypt_start_app(Config) -> - do_decrypt_start_app(Config, "hello"). - -decrypt_start_app_file(Config) -> - do_decrypt_start_app(Config, {file, ?config(data_dir, Config) ++ "/rabbit_shovel_test.passphrase"}). - -do_decrypt_start_app(Config, Passphrase) -> - %% Configure rabbit for decrypting configuration. - application:set_env(rabbit, config_entry_decoder, [ - {cipher, aes_cbc256}, - {hash, sha512}, - {iterations, 1000}, - {passphrase, Passphrase} - ], [{persistent, true}]), - %% Add the path to our test application. - code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), - %% Attempt to start our test application. - %% - %% We expect a failure *after* the decrypting has been done. - try - rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) - catch _:_ -> - ok - end, - %% Check if the values have been decrypted. - {ok, Shovels} = application:get_env(rabbit_shovel_test, shovels), - {_, FirstShovel} = lists:keyfind(my_first_shovel, 1, Shovels), - {_, Sources} = lists:keyfind(sources, 1, FirstShovel), - {_, Brokers} = lists:keyfind(brokers, 1, Sources), - ["amqp://fred:secret@host1.domain/my_vhost", - "amqp://john:secret@host2.domain/my_vhost"] = Brokers, - ok. - -decrypt_start_app_undefined(Config) -> - %% Configure rabbit for decrypting configuration. - application:set_env(rabbit, config_entry_decoder, [ - {cipher, aes_cbc256}, - {hash, sha512}, - {iterations, 1000} - %% No passphrase option! - ], [{persistent, true}]), - %% Add the path to our test application. - code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), - %% Attempt to start our test application. - %% - %% We expect a failure during decryption because the passphrase is missing. - try - rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) - catch - throw:{bad_config_entry_decoder, missing_passphrase} -> ok; - _:Exception -> exit({unexpected_exception, Exception}) - end. - -decrypt_start_app_wrong_passphrase(Config) -> - %% Configure rabbit for decrypting configuration. - application:set_env(rabbit, config_entry_decoder, [ - {cipher, aes_cbc256}, - {hash, sha512}, - {iterations, 1000}, - {passphrase, "wrong passphrase"} - ], [{persistent, true}]), - %% Add the path to our test application. - code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), - %% Attempt to start our test application. - %% - %% We expect a failure during decryption because the passphrase is wrong. - try - rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) - catch - throw:{config_decryption_error, _, _} -> ok; - _:Exception -> exit({unexpected_exception, Exception}) - end. - -rabbitmqctl_encode(_Config) -> - % list ciphers and hashes - {ok, _} = rabbit_control_pbe:list_ciphers(), - {ok, _} = rabbit_control_pbe:list_hashes(), - % incorrect ciphers, hashes and iteration number - {error, _} = rabbit_control_pbe:encode(funny_cipher, undefined, undefined, undefined), - {error, _} = rabbit_control_pbe:encode(undefined, funny_hash, undefined, undefined), - {error, _} = rabbit_control_pbe:encode(undefined, undefined, -1, undefined), - {error, _} = rabbit_control_pbe:encode(undefined, undefined, 0, undefined), - % incorrect number of arguments - {error, _} = rabbit_control_pbe:encode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [] - ), - {error, _} = rabbit_control_pbe:encode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [undefined] - ), - {error, _} = rabbit_control_pbe:encode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [undefined, undefined, undefined] - ), - - % encrypt/decrypt - % string - rabbitmqctl_encode_encrypt_decrypt("foobar"), - % binary - rabbitmqctl_encode_encrypt_decrypt("<<\"foobar\">>"), - % tuple - rabbitmqctl_encode_encrypt_decrypt("{password,<<\"secret\">>}"), - - ok. - -rabbitmqctl_encode_encrypt_decrypt(Secret) -> - PassPhrase = "passphrase", - {ok, Output} = rabbit_control_pbe:encode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [Secret, PassPhrase] - ), - {encrypted, Encrypted} = rabbit_control_pbe:evaluate_input_as_term(lists:flatten(Output)), - - {ok, Result} = rabbit_control_pbe:decode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [lists:flatten(io_lib:format("~p", [Encrypted])), PassPhrase] - ), - Secret = lists:flatten(Result), - % decrypt with {encrypted, ...} form as input - {ok, Result} = rabbit_control_pbe:decode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [lists:flatten(io_lib:format("~p", [{encrypted, Encrypted}])), PassPhrase] - ), - - % wrong passphrase - {error, _} = rabbit_control_pbe:decode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [lists:flatten(io_lib:format("~p", [Encrypted])), PassPhrase ++ " "] - ), - {error, _} = rabbit_control_pbe:decode( - rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), - [lists:flatten(io_lib:format("~p", [{encrypted, Encrypted}])), PassPhrase ++ " "] - ) - . - -rabbit_direct_extract_extra_auth_props(_Config) -> - {ok, CSC} = code_server_cache:start_link(), - % no protocol to extract - [] = rabbit_direct:extract_extra_auth_props( - {<<"guest">>, <<"guest">>}, <<"/">>, 1, - [{name,<<"127.0.0.1:52366 -> 127.0.0.1:1883">>}]), - % protocol to extract, but no module to call - [] = rabbit_direct:extract_extra_auth_props( - {<<"guest">>, <<"guest">>}, <<"/">>, 1, - [{protocol, {'PROTOCOL_WITHOUT_MODULE', "1.0"}}]), - % see rabbit_dummy_protocol_connection_info module - % protocol to extract, module that returns a client ID - [{client_id, <<"DummyClientId">>}] = rabbit_direct:extract_extra_auth_props( - {<<"guest">>, <<"guest">>}, <<"/">>, 1, - [{protocol, {'DUMMY_PROTOCOL', "1.0"}}]), - % protocol to extract, but error thrown in module - [] = rabbit_direct:extract_extra_auth_props( - {<<"guest">>, <<"guest">>}, <<"/">>, -1, - [{protocol, {'DUMMY_PROTOCOL', "1.0"}}]), - gen_server:stop(CSC), - ok. - -%% ------------------------------------------------------------------- -%% pg_local. -%% ------------------------------------------------------------------- - -pg_local(_Config) -> - [P, Q] = [spawn(fun () -> receive X -> X end end) || _ <- lists:seq(0, 1)], - check_pg_local(ok, [], []), - %% P joins group a, then b, then a again - check_pg_local(pg_local:join(a, P), [P], []), - check_pg_local(pg_local:join(b, P), [P], [P]), - check_pg_local(pg_local:join(a, P), [P, P], [P]), - %% Q joins group a, then b, then b again - check_pg_local(pg_local:join(a, Q), [P, P, Q], [P]), - check_pg_local(pg_local:join(b, Q), [P, P, Q], [P, Q]), - check_pg_local(pg_local:join(b, Q), [P, P, Q], [P, Q, Q]), - %% P leaves groups a and a - check_pg_local(pg_local:leave(a, P), [P, Q], [P, Q, Q]), - check_pg_local(pg_local:leave(b, P), [P, Q], [Q, Q]), - %% leave/2 is idempotent - check_pg_local(pg_local:leave(a, P), [Q], [Q, Q]), - check_pg_local(pg_local:leave(a, P), [Q], [Q, Q]), - %% clean up all processes - [begin X ! done, - Ref = erlang:monitor(process, X), - receive {'DOWN', Ref, process, X, _Info} -> ok end - end || X <- [P, Q]], - %% ensure the groups are empty - check_pg_local(ok, [], []), - passed. - -pg_local_with_unexpected_deaths1(_Config) -> - [A, B] = [spawn(fun () -> receive X -> X end end) || _ <- lists:seq(0, 1)], - check_pg_local(ok, [], []), - %% A joins groups a and b - check_pg_local(pg_local:join(a, A), [A], []), - check_pg_local(pg_local:join(b, A), [A], [A]), - %% B joins group b - check_pg_local(pg_local:join(b, B), [A], [A, B]), - - [begin erlang:exit(X, sleep_now_in_a_fire), - Ref = erlang:monitor(process, X), - receive {'DOWN', Ref, process, X, _Info} -> ok end - end || X <- [A, B]], - %% ensure the groups are empty - check_pg_local(ok, [], []), - ?assertNot(erlang:is_process_alive(A)), - ?assertNot(erlang:is_process_alive(B)), - - passed. - -pg_local_with_unexpected_deaths2(_Config) -> - [A, B] = [spawn(fun () -> receive X -> X end end) || _ <- lists:seq(0, 1)], - check_pg_local(ok, [], []), - %% A joins groups a and b - check_pg_local(pg_local:join(a, A), [A], []), - check_pg_local(pg_local:join(b, A), [A], [A]), - %% B joins group b - check_pg_local(pg_local:join(b, B), [A], [A, B]), - - %% something else yanks a record (or all of them) from the pg_local - %% bookkeeping table - ok = pg_local:clear(), - - [begin erlang:exit(X, sleep_now_in_a_fire), - Ref = erlang:monitor(process, X), - receive {'DOWN', Ref, process, X, _Info} -> ok end - end || X <- [A, B]], - %% ensure the groups are empty - check_pg_local(ok, [], []), - ?assertNot(erlang:is_process_alive(A)), - ?assertNot(erlang:is_process_alive(B)), - - passed. - -check_pg_local(ok, APids, BPids) -> - ok = pg_local:sync(), - ?assertEqual([true, true], [lists:sort(Pids) == lists:sort(pg_local:get_members(Key)) || - {Key, Pids} <- [{a, APids}, {b, BPids}]]). - -%% ------------------------------------------------------------------- -%% priority_queue. -%% ------------------------------------------------------------------- - -priority_queue(_Config) -> - - false = priority_queue:is_queue(not_a_queue), - - %% empty Q - Q = priority_queue:new(), - {true, true, 0, [], []} = test_priority_queue(Q), - - %% 1-4 element no-priority Q - true = lists:all(fun (X) -> X =:= passed end, - lists:map(fun test_simple_n_element_queue/1, - lists:seq(1, 4))), - - %% 1-element priority Q - Q1 = priority_queue:in(foo, 1, priority_queue:new()), - {true, false, 1, [{1, foo}], [foo]} = - test_priority_queue(Q1), - - %% 2-element same-priority Q - Q2 = priority_queue:in(bar, 1, Q1), - {true, false, 2, [{1, foo}, {1, bar}], [foo, bar]} = - test_priority_queue(Q2), - - %% 2-element different-priority Q - Q3 = priority_queue:in(bar, 2, Q1), - {true, false, 2, [{2, bar}, {1, foo}], [bar, foo]} = - test_priority_queue(Q3), - - %% 1-element negative priority Q - Q4 = priority_queue:in(foo, -1, priority_queue:new()), - {true, false, 1, [{-1, foo}], [foo]} = test_priority_queue(Q4), - - %% merge 2 * 1-element no-priority Qs - Q5 = priority_queue:join(priority_queue:in(foo, Q), - priority_queue:in(bar, Q)), - {true, false, 2, [{0, foo}, {0, bar}], [foo, bar]} = - test_priority_queue(Q5), - - %% merge 1-element no-priority Q with 1-element priority Q - Q6 = priority_queue:join(priority_queue:in(foo, Q), - priority_queue:in(bar, 1, Q)), - {true, false, 2, [{1, bar}, {0, foo}], [bar, foo]} = - test_priority_queue(Q6), - - %% merge 1-element priority Q with 1-element no-priority Q - Q7 = priority_queue:join(priority_queue:in(foo, 1, Q), - priority_queue:in(bar, Q)), - {true, false, 2, [{1, foo}, {0, bar}], [foo, bar]} = - test_priority_queue(Q7), - - %% merge 2 * 1-element same-priority Qs - Q8 = priority_queue:join(priority_queue:in(foo, 1, Q), - priority_queue:in(bar, 1, Q)), - {true, false, 2, [{1, foo}, {1, bar}], [foo, bar]} = - test_priority_queue(Q8), - - %% merge 2 * 1-element different-priority Qs - Q9 = priority_queue:join(priority_queue:in(foo, 1, Q), - priority_queue:in(bar, 2, Q)), - {true, false, 2, [{2, bar}, {1, foo}], [bar, foo]} = - test_priority_queue(Q9), - - %% merge 2 * 1-element different-priority Qs (other way around) - Q10 = priority_queue:join(priority_queue:in(bar, 2, Q), - priority_queue:in(foo, 1, Q)), - {true, false, 2, [{2, bar}, {1, foo}], [bar, foo]} = - test_priority_queue(Q10), - - %% merge 2 * 2-element multi-different-priority Qs - Q11 = priority_queue:join(Q6, Q5), - {true, false, 4, [{1, bar}, {0, foo}, {0, foo}, {0, bar}], - [bar, foo, foo, bar]} = test_priority_queue(Q11), - - %% and the other way around - Q12 = priority_queue:join(Q5, Q6), - {true, false, 4, [{1, bar}, {0, foo}, {0, bar}, {0, foo}], - [bar, foo, bar, foo]} = test_priority_queue(Q12), - - %% merge with negative priorities - Q13 = priority_queue:join(Q4, Q5), - {true, false, 3, [{0, foo}, {0, bar}, {-1, foo}], [foo, bar, foo]} = - test_priority_queue(Q13), - - %% and the other way around - Q14 = priority_queue:join(Q5, Q4), - {true, false, 3, [{0, foo}, {0, bar}, {-1, foo}], [foo, bar, foo]} = - test_priority_queue(Q14), - - %% joins with empty queues: - Q1 = priority_queue:join(Q, Q1), - Q1 = priority_queue:join(Q1, Q), - - %% insert with priority into non-empty zero-priority queue - Q15 = priority_queue:in(baz, 1, Q5), - {true, false, 3, [{1, baz}, {0, foo}, {0, bar}], [baz, foo, bar]} = - test_priority_queue(Q15), - - %% 1-element infinity priority Q - Q16 = priority_queue:in(foo, infinity, Q), - {true, false, 1, [{infinity, foo}], [foo]} = test_priority_queue(Q16), - - %% add infinity to 0-priority Q - Q17 = priority_queue:in(foo, infinity, priority_queue:in(bar, Q)), - {true, false, 2, [{infinity, foo}, {0, bar}], [foo, bar]} = - test_priority_queue(Q17), - - %% and the other way around - Q18 = priority_queue:in(bar, priority_queue:in(foo, infinity, Q)), - {true, false, 2, [{infinity, foo}, {0, bar}], [foo, bar]} = - test_priority_queue(Q18), - - %% add infinity to mixed-priority Q - Q19 = priority_queue:in(qux, infinity, Q3), - {true, false, 3, [{infinity, qux}, {2, bar}, {1, foo}], [qux, bar, foo]} = - test_priority_queue(Q19), - - %% merge the above with a negative priority Q - Q20 = priority_queue:join(Q19, Q4), - {true, false, 4, [{infinity, qux}, {2, bar}, {1, foo}, {-1, foo}], - [qux, bar, foo, foo]} = test_priority_queue(Q20), - - %% merge two infinity priority queues - Q21 = priority_queue:join(priority_queue:in(foo, infinity, Q), - priority_queue:in(bar, infinity, Q)), - {true, false, 2, [{infinity, foo}, {infinity, bar}], [foo, bar]} = - test_priority_queue(Q21), - - %% merge two mixed priority with infinity queues - Q22 = priority_queue:join(Q18, Q20), - {true, false, 6, [{infinity, foo}, {infinity, qux}, {2, bar}, {1, foo}, - {0, bar}, {-1, foo}], [foo, qux, bar, foo, bar, foo]} = - test_priority_queue(Q22), - - passed. - -priority_queue_in_all(Q, L) -> - lists:foldl(fun (X, Acc) -> priority_queue:in(X, Acc) end, Q, L). - -priority_queue_out_all(Q) -> - case priority_queue:out(Q) of - {empty, _} -> []; - {{value, V}, Q1} -> [V | priority_queue_out_all(Q1)] - end. - -test_priority_queue(Q) -> - {priority_queue:is_queue(Q), - priority_queue:is_empty(Q), - priority_queue:len(Q), - priority_queue:to_list(Q), - priority_queue_out_all(Q)}. - -test_simple_n_element_queue(N) -> - Items = lists:seq(1, N), - Q = priority_queue_in_all(priority_queue:new(), Items), - ToListRes = [{0, X} || X <- Items], - {true, false, N, ToListRes, Items} = test_priority_queue(Q), - passed. - - -%% --------------------------------------------------------------------------- -%% supervisor2. -%% --------------------------------------------------------------------------- - -check_shutdown_stop(_Config) -> - ok = check_shutdown(stop, 200, 200, 2000). - -check_shutdown_ignored(_Config) -> - ok = check_shutdown(ignored, 1, 2, 2000). - -check_shutdown(SigStop, Iterations, ChildCount, SupTimeout) -> - {ok, Sup} = supervisor2:start_link(dummy_supervisor2, [SupTimeout]), - Res = lists:foldl( - fun (I, ok) -> - TestSupPid = erlang:whereis(dummy_supervisor2), - ChildPids = - [begin - {ok, ChildPid} = - supervisor2:start_child(TestSupPid, []), - ChildPid - end || _ <- lists:seq(1, ChildCount)], - MRef = erlang:monitor(process, TestSupPid), - [P ! SigStop || P <- ChildPids], - ok = supervisor2:terminate_child(Sup, test_sup), - {ok, _} = supervisor2:restart_child(Sup, test_sup), - receive - {'DOWN', MRef, process, TestSupPid, shutdown} -> - ok; - {'DOWN', MRef, process, TestSupPid, Reason} -> - {error, {I, Reason}} - end; - (_, R) -> - R - end, ok, lists:seq(1, Iterations)), - unlink(Sup), - MSupRef = erlang:monitor(process, Sup), - exit(Sup, shutdown), - receive - {'DOWN', MSupRef, process, Sup, _Reason} -> - ok - end, - Res. - -%% --------------------------------------------------------------------------- -%% vm_memory_monitor. -%% --------------------------------------------------------------------------- - -parse_line_linux(_Config) -> - lists:foreach(fun ({S, {K, V}}) -> - {K, V} = vm_memory_monitor:parse_line_linux(S) - end, - [{"MemTotal: 0 kB", {'MemTotal', 0}}, - {"MemTotal: 502968 kB ", {'MemTotal', 515039232}}, - {"MemFree: 178232 kB", {'MemFree', 182509568}}, - {"MemTotal: 50296888", {'MemTotal', 50296888}}, - {"MemTotal 502968 kB", {'MemTotal', 515039232}}, - {"MemTotal 50296866 ", {'MemTotal', 50296866}}]), - ok. - -%% --------------------------------------------------------------------------- -%% Unordered tests (originally from rabbit_tests.erl). -%% --------------------------------------------------------------------------- - -%% Test that content frames don't exceed frame-max -content_framing(_Config) -> - %% no content - passed = test_content_framing(4096, <<>>), - %% easily fit in one frame - passed = test_content_framing(4096, <<"Easy">>), - %% exactly one frame (empty frame = 8 bytes) - passed = test_content_framing(11, <<"One">>), - %% more than one frame - passed = test_content_framing(11, <<"More than one frame">>), - passed. - -test_content_framing(FrameMax, BodyBin) -> - [Header | Frames] = - rabbit_binary_generator:build_simple_content_frames( - 1, - rabbit_binary_generator:ensure_content_encoded( - rabbit_basic:build_content(#'P_basic'{}, BodyBin), - rabbit_framing_amqp_0_9_1), - FrameMax, - rabbit_framing_amqp_0_9_1), - %% header is formatted correctly and the size is the total of the - %% fragments - <<_FrameHeader:7/binary, _ClassAndWeight:4/binary, - BodySize:64/unsigned, _Rest/binary>> = list_to_binary(Header), - BodySize = size(BodyBin), - true = lists:all( - fun (ContentFrame) -> - FrameBinary = list_to_binary(ContentFrame), - %% assert - <<_TypeAndChannel:3/binary, - Size:32/unsigned, _Payload:Size/binary, 16#CE>> = - FrameBinary, - size(FrameBinary) =< FrameMax - end, Frames), - passed. - -content_transcoding(_Config) -> - %% there are no guarantees provided by 'clear' - it's just a hint - ClearDecoded = fun rabbit_binary_parser:clear_decoded_content/1, - ClearEncoded = fun rabbit_binary_generator:clear_encoded_content/1, - EnsureDecoded = - fun (C0) -> - C1 = rabbit_binary_parser:ensure_content_decoded(C0), - true = C1#content.properties =/= none, - C1 - end, - EnsureEncoded = - fun (Protocol) -> - fun (C0) -> - C1 = rabbit_binary_generator:ensure_content_encoded( - C0, Protocol), - true = C1#content.properties_bin =/= none, - C1 - end - end, - %% Beyond the assertions in Ensure*, the only testable guarantee - %% is that the operations should never fail. - %% - %% If we were using quickcheck we'd simply stuff all the above - %% into a generator for sequences of operations. In the absence of - %% quickcheck we pick particularly interesting sequences that: - %% - %% - execute every op twice since they are idempotent - %% - invoke clear_decoded, clear_encoded, decode and transcode - %% with one or both of decoded and encoded content present - [begin - sequence_with_content([Op]), - sequence_with_content([ClearEncoded, Op]), - sequence_with_content([ClearDecoded, Op]) - end || Op <- [ClearDecoded, ClearEncoded, EnsureDecoded, - EnsureEncoded(rabbit_framing_amqp_0_9_1), - EnsureEncoded(rabbit_framing_amqp_0_8)]], - passed. - -sequence_with_content(Sequence) -> - lists:foldl(fun (F, V) -> F(F(V)) end, - rabbit_binary_generator:ensure_content_encoded( - rabbit_basic:build_content(#'P_basic'{}, <<>>), - rabbit_framing_amqp_0_9_1), - Sequence). - -pmerge(_Config) -> - P = [{a, 1}, {b, 2}], - P = rabbit_misc:pmerge(a, 3, P), - [{c, 3} | P] = rabbit_misc:pmerge(c, 3, P), - passed. - -plmerge(_Config) -> - P1 = [{a, 1}, {b, 2}, {c, 3}], - P2 = [{a, 2}, {d, 4}], - [{a, 1}, {b, 2}, {c, 3}, {d, 4}] = rabbit_misc:plmerge(P1, P2), - passed. - -merge_operator_policy_definitions(_Config) -> - P1 = undefined, - P2 = [{definition, [{<<"message-ttl">>, 3000}]}], - ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P1, P2)), - ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P2, P1)), - - ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P1, rabbit_data_coercion:to_map(P2))), - ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(rabbit_data_coercion:to_map(P2), P1)), - - ?assertEqual(undefined, rabbit_policy:merge_operator_definitions(undefined, undefined)), - - ?assertEqual([], rabbit_policy:merge_operator_definitions([], [])), - ?assertEqual([], rabbit_policy:merge_operator_definitions(#{}, [])), - ?assertEqual([], rabbit_policy:merge_operator_definitions(#{}, #{})), - ?assertEqual([], rabbit_policy:merge_operator_definitions([], #{})), - - %% operator policy takes precedence - ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions( - [{definition, [ - {<<"message-ttl">>, 5000} - ]}], - [{definition, [ - {<<"message-ttl">>, 3000} - ]}] - )), - - ?assertEqual([{<<"delivery-limit">>, 20}, - {<<"message-ttl">>, 3000}], - rabbit_policy:merge_operator_definitions( - [{definition, [ - {<<"message-ttl">>, 5000}, - {<<"delivery-limit">>, 20} - ]}], - [{definition, [ - {<<"message-ttl">>, 3000} - ]}]) - ), - - ?assertEqual( - [{<<"delivery-limit">>, 20}, - {<<"message-ttl">>, 3000}, - {<<"unknown">>, <<"value">>}], - - rabbit_policy:merge_operator_definitions( - #{definition => #{ - <<"message-ttl">> => 5000, - <<"delivery-limit">> => 20 - }}, - #{definition => #{ - <<"message-ttl">> => 3000, - <<"unknown">> => <<"value">> - }}) - ), - - ?assertEqual( - [{<<"delivery-limit">>, 20}, - {<<"message-ttl">>, 3000}], - - rabbit_policy:merge_operator_definitions( - #{definition => #{ - <<"message-ttl">> => 5000, - <<"delivery-limit">> => 20 - }}, - [{definition, [ - {<<"message-ttl">>, 3000} - ]}]) - ), - - passed. - -table_codec(_Config) -> - %% FIXME this does not test inexact numbers (double and float) yet, - %% because they won't pass the equality assertions - Table = [{<<"longstr">>, longstr, <<"Here is a long string">>}, - {<<"signedint">>, signedint, 12345}, - {<<"decimal">>, decimal, {3, 123456}}, - {<<"timestamp">>, timestamp, 109876543209876}, - {<<"table">>, table, [{<<"one">>, signedint, 54321}, - {<<"two">>, longstr, - <<"A long string">>}]}, - {<<"byte">>, byte, -128}, - {<<"long">>, long, 1234567890}, - {<<"short">>, short, 655}, - {<<"bool">>, bool, true}, - {<<"binary">>, binary, <<"a binary string">>}, - {<<"unsignedbyte">>, unsignedbyte, 250}, - {<<"unsignedshort">>, unsignedshort, 65530}, - {<<"unsignedint">>, unsignedint, 4294967290}, - {<<"void">>, void, undefined}, - {<<"array">>, array, [{signedint, 54321}, - {longstr, <<"A long string">>}]} - ], - Binary = << - 7,"longstr", "S", 21:32, "Here is a long string", - 9,"signedint", "I", 12345:32/signed, - 7,"decimal", "D", 3, 123456:32, - 9,"timestamp", "T", 109876543209876:64, - 5,"table", "F", 31:32, % length of table - 3,"one", "I", 54321:32, - 3,"two", "S", 13:32, "A long string", - 4,"byte", "b", -128:8/signed, - 4,"long", "l", 1234567890:64, - 5,"short", "s", 655:16, - 4,"bool", "t", 1, - 6,"binary", "x", 15:32, "a binary string", - 12,"unsignedbyte", "B", 250:8/unsigned, - 13,"unsignedshort", "u", 65530:16/unsigned, - 11,"unsignedint", "i", 4294967290:32/unsigned, - 4,"void", "V", - 5,"array", "A", 23:32, - "I", 54321:32, - "S", 13:32, "A long string" - >>, - Binary = rabbit_binary_generator:generate_table(Table), - Table = rabbit_binary_parser:parse_table(Binary), - passed. - -unfold(_Config) -> - {[], test} = rabbit_misc:unfold(fun (_V) -> false end, test), - List = lists:seq(2,20,2), - {List, 0} = rabbit_misc:unfold(fun (0) -> false; - (N) -> {true, N*2, N-1} - end, 10), - passed. - -listing_plugins_from_multiple_directories(Config) -> - %% Generate some fake plugins in .ez files - FirstDir = filename:join([?config(priv_dir, Config), "listing_plugins_from_multiple_directories-1"]), - SecondDir = filename:join([?config(priv_dir, Config), "listing_plugins_from_multiple_directories-2"]), - ok = file:make_dir(FirstDir), - ok = file:make_dir(SecondDir), - lists:foreach(fun({Dir, AppName, Vsn}) -> - EzName = filename:join([Dir, io_lib:format("~s-~s.ez", [AppName, Vsn])]), - AppFileName = lists:flatten(io_lib:format("~s-~s/ebin/~s.app", [AppName, Vsn, AppName])), - AppFileContents = list_to_binary( - io_lib:format( - "~p.", - [{application, AppName, - [{vsn, Vsn}, - {applications, [kernel, stdlib, rabbit]}]}])), - {ok, {_, EzData}} = zip:zip(EzName, [{AppFileName, AppFileContents}], [memory]), - ok = file:write_file(EzName, EzData) - end, - [{FirstDir, plugin_first_dir, "3"}, - {SecondDir, plugin_second_dir, "4"}, - {FirstDir, plugin_both, "1"}, - {SecondDir, plugin_both, "2"}]), - - %% Everything was collected from both directories, plugin with higher - %% version should take precedence - PathSep = case os:type() of - {win32, _} -> ";"; - _ -> ":" - end, - Path = FirstDir ++ PathSep ++ SecondDir, - Got = lists:sort([{Name, Vsn} || #plugin{name = Name, version = Vsn} <- rabbit_plugins:list(Path)]), - %% `rabbit` was loaded automatically by `rabbit_plugins:list/1`. - %% We want to unload it now so it does not interfere with other - %% testcases. - application:unload(rabbit), - Expected = [{plugin_both, "2"}, {plugin_first_dir, "3"}, {plugin_second_dir, "4"}], - case Got of - Expected -> - ok; - _ -> - ct:pal("Got ~p~nExpected: ~p", [Got, Expected]), - exit({wrong_plugins_list, Got}) - end, - ok. - -%% -%% Access Control -%% - -auth_backend_internal_expand_topic_permission(_Config) -> - ExpandMap = #{<<"username">> => <<"guest">>, <<"vhost">> => <<"default">>}, - %% simple case - <<"services/default/accounts/guest/notifications">> = - rabbit_auth_backend_internal:expand_topic_permission( - <<"services/{vhost}/accounts/{username}/notifications">>, - ExpandMap - ), - %% replace variable twice - <<"services/default/accounts/default/guest/notifications">> = - rabbit_auth_backend_internal:expand_topic_permission( - <<"services/{vhost}/accounts/{vhost}/{username}/notifications">>, - ExpandMap - ), - %% nothing to replace - <<"services/accounts/notifications">> = - rabbit_auth_backend_internal:expand_topic_permission( - <<"services/accounts/notifications">>, - ExpandMap - ), - %% the expand map isn't defined - <<"services/{vhost}/accounts/{username}/notifications">> = - rabbit_auth_backend_internal:expand_topic_permission( - <<"services/{vhost}/accounts/{username}/notifications">>, - undefined - ), - %% the expand map is empty - <<"services/{vhost}/accounts/{username}/notifications">> = - rabbit_auth_backend_internal:expand_topic_permission( - <<"services/{vhost}/accounts/{username}/notifications">>, - #{} - ), - ok. diff --git a/test/unit_amqp091_content_framing_SUITE.erl b/test/unit_amqp091_content_framing_SUITE.erl new file mode 100644 index 0000000000..9400df672a --- /dev/null +++ b/test/unit_amqp091_content_framing_SUITE.erl @@ -0,0 +1,240 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_amqp091_content_framing_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). +-include_lib("rabbit_common/include/rabbit_framing.hrl"). + +-compile(export_all). + +all() -> + [ + {group, parallel_tests} + ]. + +groups() -> + [ + {parallel_tests, [parallel], [ + write_table_with_invalid_existing_type, + invalid_existing_headers, + disparate_invalid_header_entries_accumulate_separately, + corrupt_or_invalid_headers_are_overwritten, + invalid_same_header_entry_accumulation, + content_framing, + content_transcoding, + table_codec + ]} + ]. + +%% ------------------------------------------------------------------- +%% Test Cases +%% ------------------------------------------------------------------- + +-define(XDEATH_TABLE, + [{<<"reason">>, longstr, <<"blah">>}, + {<<"queue">>, longstr, <<"foo.bar.baz">>}, + {<<"exchange">>, longstr, <<"my-exchange">>}, + {<<"routing-keys">>, array, []}]). + +-define(ROUTE_TABLE, [{<<"redelivered">>, bool, <<"true">>}]). + +-define(BAD_HEADER(K), {<<K>>, longstr, <<"bad ", K>>}). +-define(BAD_HEADER2(K, Suf), {<<K>>, longstr, <<"bad ", K, Suf>>}). +-define(FOUND_BAD_HEADER(K), {<<K>>, array, [{longstr, <<"bad ", K>>}]}). + +write_table_with_invalid_existing_type(_Config) -> + prepend_check(<<"header1">>, ?XDEATH_TABLE, [?BAD_HEADER("header1")]). + +invalid_existing_headers(_Config) -> + Headers = + prepend_check(<<"header2">>, ?ROUTE_TABLE, [?BAD_HEADER("header2")]), + {array, [{table, ?ROUTE_TABLE}]} = + rabbit_misc:table_lookup(Headers, <<"header2">>), + passed. + +disparate_invalid_header_entries_accumulate_separately(_Config) -> + BadHeaders = [?BAD_HEADER("header2")], + Headers = prepend_check(<<"header2">>, ?ROUTE_TABLE, BadHeaders), + Headers2 = prepend_check(<<"header1">>, ?XDEATH_TABLE, + [?BAD_HEADER("header1") | Headers]), + {table, [?FOUND_BAD_HEADER("header1"), + ?FOUND_BAD_HEADER("header2")]} = + rabbit_misc:table_lookup(Headers2, ?INVALID_HEADERS_KEY), + passed. + +corrupt_or_invalid_headers_are_overwritten(_Config) -> + Headers0 = [?BAD_HEADER("header1"), + ?BAD_HEADER("x-invalid-headers")], + Headers1 = prepend_check(<<"header1">>, ?XDEATH_TABLE, Headers0), + {table,[?FOUND_BAD_HEADER("header1"), + ?FOUND_BAD_HEADER("x-invalid-headers")]} = + rabbit_misc:table_lookup(Headers1, ?INVALID_HEADERS_KEY), + passed. + +invalid_same_header_entry_accumulation(_Config) -> + BadHeader1 = ?BAD_HEADER2("header1", "a"), + Headers = prepend_check(<<"header1">>, ?ROUTE_TABLE, [BadHeader1]), + Headers2 = prepend_check(<<"header1">>, ?ROUTE_TABLE, + [?BAD_HEADER2("header1", "b") | Headers]), + {table, InvalidHeaders} = + rabbit_misc:table_lookup(Headers2, ?INVALID_HEADERS_KEY), + {array, [{longstr,<<"bad header1b">>}, + {longstr,<<"bad header1a">>}]} = + rabbit_misc:table_lookup(InvalidHeaders, <<"header1">>), + passed. + +prepend_check(HeaderKey, HeaderTable, Headers) -> + Headers1 = rabbit_basic:prepend_table_header( + HeaderKey, HeaderTable, Headers), + {table, Invalid} = + rabbit_misc:table_lookup(Headers1, ?INVALID_HEADERS_KEY), + {Type, Value} = rabbit_misc:table_lookup(Headers, HeaderKey), + {array, [{Type, Value} | _]} = + rabbit_misc:table_lookup(Invalid, HeaderKey), + Headers1. + + +%% Test that content frames don't exceed frame-max +content_framing(_Config) -> + %% no content + passed = test_content_framing(4096, <<>>), + %% easily fit in one frame + passed = test_content_framing(4096, <<"Easy">>), + %% exactly one frame (empty frame = 8 bytes) + passed = test_content_framing(11, <<"One">>), + %% more than one frame + passed = test_content_framing(11, <<"More than one frame">>), + passed. + +test_content_framing(FrameMax, BodyBin) -> + [Header | Frames] = + rabbit_binary_generator:build_simple_content_frames( + 1, + rabbit_binary_generator:ensure_content_encoded( + rabbit_basic:build_content(#'P_basic'{}, BodyBin), + rabbit_framing_amqp_0_9_1), + FrameMax, + rabbit_framing_amqp_0_9_1), + %% header is formatted correctly and the size is the total of the + %% fragments + <<_FrameHeader:7/binary, _ClassAndWeight:4/binary, + BodySize:64/unsigned, _Rest/binary>> = list_to_binary(Header), + BodySize = size(BodyBin), + true = lists:all( + fun (ContentFrame) -> + FrameBinary = list_to_binary(ContentFrame), + %% assert + <<_TypeAndChannel:3/binary, + Size:32/unsigned, _Payload:Size/binary, 16#CE>> = + FrameBinary, + size(FrameBinary) =< FrameMax + end, Frames), + passed. + +content_transcoding(_Config) -> + %% there are no guarantees provided by 'clear' - it's just a hint + ClearDecoded = fun rabbit_binary_parser:clear_decoded_content/1, + ClearEncoded = fun rabbit_binary_generator:clear_encoded_content/1, + EnsureDecoded = + fun (C0) -> + C1 = rabbit_binary_parser:ensure_content_decoded(C0), + true = C1#content.properties =/= none, + C1 + end, + EnsureEncoded = + fun (Protocol) -> + fun (C0) -> + C1 = rabbit_binary_generator:ensure_content_encoded( + C0, Protocol), + true = C1#content.properties_bin =/= none, + C1 + end + end, + %% Beyond the assertions in Ensure*, the only testable guarantee + %% is that the operations should never fail. + %% + %% If we were using quickcheck we'd simply stuff all the above + %% into a generator for sequences of operations. In the absence of + %% quickcheck we pick particularly interesting sequences that: + %% + %% - execute every op twice since they are idempotent + %% - invoke clear_decoded, clear_encoded, decode and transcode + %% with one or both of decoded and encoded content present + [begin + sequence_with_content([Op]), + sequence_with_content([ClearEncoded, Op]), + sequence_with_content([ClearDecoded, Op]) + end || Op <- [ClearDecoded, ClearEncoded, EnsureDecoded, + EnsureEncoded(rabbit_framing_amqp_0_9_1), + EnsureEncoded(rabbit_framing_amqp_0_8)]], + passed. + +sequence_with_content(Sequence) -> + lists:foldl(fun (F, V) -> F(F(V)) end, + rabbit_binary_generator:ensure_content_encoded( + rabbit_basic:build_content(#'P_basic'{}, <<>>), + rabbit_framing_amqp_0_9_1), + Sequence). + +table_codec(_Config) -> + %% Note: this does not test inexact numbers (double and float) at the moment. + %% They won't pass the equality assertions. + Table = [{<<"longstr">>, longstr, <<"Here is a long string">>}, + {<<"signedint">>, signedint, 12345}, + {<<"decimal">>, decimal, {3, 123456}}, + {<<"timestamp">>, timestamp, 109876543209876}, + {<<"table">>, table, [{<<"one">>, signedint, 54321}, + {<<"two">>, longstr, + <<"A long string">>}]}, + {<<"byte">>, byte, -128}, + {<<"long">>, long, 1234567890}, + {<<"short">>, short, 655}, + {<<"bool">>, bool, true}, + {<<"binary">>, binary, <<"a binary string">>}, + {<<"unsignedbyte">>, unsignedbyte, 250}, + {<<"unsignedshort">>, unsignedshort, 65530}, + {<<"unsignedint">>, unsignedint, 4294967290}, + {<<"void">>, void, undefined}, + {<<"array">>, array, [{signedint, 54321}, + {longstr, <<"A long string">>}]} + ], + Binary = << + 7,"longstr", "S", 21:32, "Here is a long string", + 9,"signedint", "I", 12345:32/signed, + 7,"decimal", "D", 3, 123456:32, + 9,"timestamp", "T", 109876543209876:64, + 5,"table", "F", 31:32, % length of table + 3,"one", "I", 54321:32, + 3,"two", "S", 13:32, "A long string", + 4,"byte", "b", -128:8/signed, + 4,"long", "l", 1234567890:64, + 5,"short", "s", 655:16, + 4,"bool", "t", 1, + 6,"binary", "x", 15:32, "a binary string", + 12,"unsignedbyte", "B", 250:8/unsigned, + 13,"unsignedshort", "u", 65530:16/unsigned, + 11,"unsignedint", "i", 4294967290:32/unsigned, + 4,"void", "V", + 5,"array", "A", 23:32, + "I", 54321:32, + "S", 13:32, "A long string" + >>, + Binary = rabbit_binary_generator:generate_table(Table), + Table = rabbit_binary_parser:parse_table(Binary), + passed. diff --git a/test/unit_collections_SUITE.erl b/test/unit_collections_SUITE.erl new file mode 100644 index 0000000000..d07e3469d1 --- /dev/null +++ b/test/unit_collections_SUITE.erl @@ -0,0 +1,60 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_collections_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, parallel_tests} + ]. + +groups() -> + [ + {parallel_tests, [parallel], [ + pmerge, + plmerge, + unfold + ]} + ]. + +%% ------------------------------------------------------------------- +%% Test Cases +%% ------------------------------------------------------------------- + +pmerge(_Config) -> + P = [{a, 1}, {b, 2}], + P = rabbit_misc:pmerge(a, 3, P), + [{c, 3} | P] = rabbit_misc:pmerge(c, 3, P), + passed. + +plmerge(_Config) -> + P1 = [{a, 1}, {b, 2}, {c, 3}], + P2 = [{a, 2}, {d, 4}], + [{a, 1}, {b, 2}, {c, 3}, {d, 4}] = rabbit_misc:plmerge(P1, P2), + passed. + +unfold(_Config) -> + {[], test} = rabbit_misc:unfold(fun (_V) -> false end, test), + List = lists:seq(2,20,2), + {List, 0} = rabbit_misc:unfold(fun (0) -> false; + (N) -> {true, N*2, N-1} + end, 10), + passed. diff --git a/test/unit_config_value_encryption_SUITE.erl b/test/unit_config_value_encryption_SUITE.erl new file mode 100644 index 0000000000..1d808c4993 --- /dev/null +++ b/test/unit_config_value_encryption_SUITE.erl @@ -0,0 +1,242 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_config_value_encryption_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, sequential_tests} + ]. + +groups() -> + [ + {sequential_tests, [], [ + decrypt_start_app, + decrypt_start_app_file, + decrypt_start_app_undefined, + decrypt_start_app_wrong_passphrase, + decrypt_config, + rabbitmqctl_encode + ]} + ]. + +init_per_testcase(TC, Config) when TC =:= decrypt_start_app; + TC =:= decrypt_start_app_file; + TC =:= decrypt_start_app_undefined; + TC =:= decrypt_start_app_wrong_passphrase -> + application:set_env(rabbit, feature_flags_file, "", [{persistent, true}]), + Config; +init_per_testcase(_Testcase, Config) -> + Config. + +end_per_testcase(_TC, _Config) -> + ok. + +%% ------------------------------------------------------------------- +%% Test Cases +%% ------------------------------------------------------------------- + +decrypt_config(_Config) -> + %% Take all available block ciphers. + Hashes = rabbit_pbe:supported_hashes(), + Ciphers = rabbit_pbe:supported_ciphers(), + Iterations = [1, 10, 100, 1000], + %% Loop through all hashes, ciphers and iterations. + _ = [begin + PassPhrase = crypto:strong_rand_bytes(16), + do_decrypt_config({C, H, I, PassPhrase}) + end || H <- Hashes, C <- Ciphers, I <- Iterations], + ok. + +do_decrypt_config(Algo = {C, H, I, P}) -> + ok = application:load(rabbit), + RabbitConfig = application:get_all_env(rabbit), + %% Encrypt a few values in configuration. + %% Common cases. + _ = [encrypt_value(Key, Algo) || Key <- [ + tcp_listeners, + num_tcp_acceptors, + ssl_options, + vm_memory_high_watermark, + default_pass, + default_permissions, + cluster_nodes, + auth_mechanisms, + msg_store_credit_disc_bound]], + %% Special case: encrypt a value in a list. + {ok, [LoopbackUser]} = application:get_env(rabbit, loopback_users), + EncLoopbackUser = rabbit_pbe:encrypt_term(C, H, I, P, LoopbackUser), + application:set_env(rabbit, loopback_users, [{encrypted, EncLoopbackUser}]), + %% Special case: encrypt a value in a key/value list. + {ok, TCPOpts} = application:get_env(rabbit, tcp_listen_options), + {_, Backlog} = lists:keyfind(backlog, 1, TCPOpts), + {_, Linger} = lists:keyfind(linger, 1, TCPOpts), + EncBacklog = rabbit_pbe:encrypt_term(C, H, I, P, Backlog), + EncLinger = rabbit_pbe:encrypt_term(C, H, I, P, Linger), + TCPOpts1 = lists:keyreplace(backlog, 1, TCPOpts, {backlog, {encrypted, EncBacklog}}), + TCPOpts2 = lists:keyreplace(linger, 1, TCPOpts1, {linger, {encrypted, EncLinger}}), + application:set_env(rabbit, tcp_listen_options, TCPOpts2), + %% Decrypt configuration. + rabbit_prelaunch_conf:decrypt_config([rabbit], Algo), + %% Check that configuration was decrypted properly. + RabbitConfig = application:get_all_env(rabbit), + ok = application:unload(rabbit), + ok. + +encrypt_value(Key, {C, H, I, P}) -> + {ok, Value} = application:get_env(rabbit, Key), + EncValue = rabbit_pbe:encrypt_term(C, H, I, P, Value), + application:set_env(rabbit, Key, {encrypted, EncValue}). + +decrypt_start_app(Config) -> + do_decrypt_start_app(Config, "hello"). + +decrypt_start_app_file(Config) -> + do_decrypt_start_app(Config, {file, ?config(data_dir, Config) ++ "/rabbit_shovel_test.passphrase"}). + +do_decrypt_start_app(Config, Passphrase) -> + %% Configure rabbit for decrypting configuration. + application:set_env(rabbit, config_entry_decoder, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000}, + {passphrase, Passphrase} + ], [{persistent, true}]), + %% Add the path to our test application. + code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), + %% Attempt to start our test application. + %% + %% We expect a failure *after* the decrypting has been done. + try + rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) + catch _:_ -> + ok + end, + %% Check if the values have been decrypted. + {ok, Shovels} = application:get_env(rabbit_shovel_test, shovels), + {_, FirstShovel} = lists:keyfind(my_first_shovel, 1, Shovels), + {_, Sources} = lists:keyfind(sources, 1, FirstShovel), + {_, Brokers} = lists:keyfind(brokers, 1, Sources), + ["amqp://fred:secret@host1.domain/my_vhost", + "amqp://john:secret@host2.domain/my_vhost"] = Brokers, + ok. + +decrypt_start_app_undefined(Config) -> + %% Configure rabbit for decrypting configuration. + application:set_env(rabbit, config_entry_decoder, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000} + %% No passphrase option! + ], [{persistent, true}]), + %% Add the path to our test application. + code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), + %% Attempt to start our test application. + %% + %% We expect a failure during decryption because the passphrase is missing. + try + rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) + catch + throw:{bad_config_entry_decoder, missing_passphrase} -> ok; + _:Exception -> exit({unexpected_exception, Exception}) + end. + +decrypt_start_app_wrong_passphrase(Config) -> + %% Configure rabbit for decrypting configuration. + application:set_env(rabbit, config_entry_decoder, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000}, + {passphrase, "wrong passphrase"} + ], [{persistent, true}]), + %% Add the path to our test application. + code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), + %% Attempt to start our test application. + %% + %% We expect a failure during decryption because the passphrase is wrong. + try + rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) + catch + throw:{config_decryption_error, _, _} -> ok; + _:Exception -> exit({unexpected_exception, Exception}) + end. + +rabbitmqctl_encode(_Config) -> + % list ciphers and hashes + {ok, _} = rabbit_control_pbe:list_ciphers(), + {ok, _} = rabbit_control_pbe:list_hashes(), + % incorrect ciphers, hashes and iteration number + {error, _} = rabbit_control_pbe:encode(funny_cipher, undefined, undefined, undefined), + {error, _} = rabbit_control_pbe:encode(undefined, funny_hash, undefined, undefined), + {error, _} = rabbit_control_pbe:encode(undefined, undefined, -1, undefined), + {error, _} = rabbit_control_pbe:encode(undefined, undefined, 0, undefined), + % incorrect number of arguments + {error, _} = rabbit_control_pbe:encode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [] + ), + {error, _} = rabbit_control_pbe:encode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [undefined] + ), + {error, _} = rabbit_control_pbe:encode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [undefined, undefined, undefined] + ), + + % encrypt/decrypt + % string + rabbitmqctl_encode_encrypt_decrypt("foobar"), + % binary + rabbitmqctl_encode_encrypt_decrypt("<<\"foobar\">>"), + % tuple + rabbitmqctl_encode_encrypt_decrypt("{password,<<\"secret\">>}"), + + ok. + +rabbitmqctl_encode_encrypt_decrypt(Secret) -> + PassPhrase = "passphrase", + {ok, Output} = rabbit_control_pbe:encode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [Secret, PassPhrase] + ), + {encrypted, Encrypted} = rabbit_control_pbe:evaluate_input_as_term(lists:flatten(Output)), + + {ok, Result} = rabbit_control_pbe:decode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [Encrypted])), PassPhrase] + ), + Secret = lists:flatten(Result), + % decrypt with {encrypted, ...} form as input + {ok, Result} = rabbit_control_pbe:decode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [{encrypted, Encrypted}])), PassPhrase] + ), + + % wrong passphrase + {error, _} = rabbit_control_pbe:decode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [Encrypted])), PassPhrase ++ " "] + ), + {error, _} = rabbit_control_pbe:decode( + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [{encrypted, Encrypted}])), PassPhrase ++ " "] + ). diff --git a/test/unit_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app b/test/unit_config_value_encryption_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app index a8481c9aa4..a8481c9aa4 100644 --- a/test/unit_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app +++ b/test/unit_config_value_encryption_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app diff --git a/test/unit_SUITE_data/rabbit_shovel_test.passphrase b/test/unit_config_value_encryption_SUITE_data/rabbit_shovel_test.passphrase index ce01362503..ce01362503 100644 --- a/test/unit_SUITE_data/rabbit_shovel_test.passphrase +++ b/test/unit_config_value_encryption_SUITE_data/rabbit_shovel_test.passphrase diff --git a/test/unit_disk_monitor_SUITE.erl b/test/unit_disk_monitor_SUITE.erl index 87ce6f8d2d..2decb5a07a 100644 --- a/test/unit_disk_monitor_SUITE.erl +++ b/test/unit_disk_monitor_SUITE.erl @@ -31,8 +31,6 @@ all() -> groups() -> [ {sequential_tests, [], [ - disk_monitor, - disk_monitor_enable, set_disk_free_limit_command ]} ]. @@ -78,10 +76,6 @@ set_disk_free_limit_command(Config) -> ?MODULE, set_disk_free_limit_command1, [Config]). set_disk_free_limit_command1(_Config) -> - %% use an absolute value - rabbit_disk_monitor:set_disk_free_limit("2000kiB"), - ?assertEqual(2048000, rabbit_disk_monitor:get_disk_free_limit()), - %% Use an integer rabbit_disk_monitor:set_disk_free_limit({mem_relative, 1}), disk_free_limit_to_total_memory_ratio_is(1), @@ -90,7 +84,12 @@ set_disk_free_limit_command1(_Config) -> rabbit_disk_monitor:set_disk_free_limit({mem_relative, 1.5}), disk_free_limit_to_total_memory_ratio_is(1.5), + %% use an absolute value + rabbit_disk_monitor:set_disk_free_limit("70MiB"), + ?assertEqual(73400320, rabbit_disk_monitor:get_disk_free_limit()), + rabbit_disk_monitor:set_disk_free_limit("50MB"), + ?assertEqual(50 * 1000 * 1000, rabbit_disk_monitor:get_disk_free_limit()), passed. disk_free_limit_to_total_memory_ratio_is(MemRatio) -> @@ -98,53 +97,3 @@ disk_free_limit_to_total_memory_ratio_is(MemRatio) -> % Total memory is unstable, so checking order true = ExpectedLimit/rabbit_disk_monitor:get_disk_free_limit() < 1.2, true = ExpectedLimit/rabbit_disk_monitor:get_disk_free_limit() > 0.98. - - -disk_monitor(Config) -> - passed = rabbit_ct_broker_helpers:rpc(Config, 0, - ?MODULE, disk_monitor1, [Config]). - -disk_monitor1(_Config) -> - %% Issue: rabbitmq-server #91 - %% os module could be mocked using 'unstick', however it may have undesired - %% side effects in following tests. Thus, we mock at rabbit_misc level - ok = meck:new(rabbit_misc, [passthrough]), - ok = meck:expect(rabbit_misc, os_cmd, fun(_) -> "\n" end), - ok = rabbit_sup:stop_child(rabbit_disk_monitor_sup), - ok = rabbit_sup:start_delayed_restartable_child(rabbit_disk_monitor, [1000]), - meck:unload(rabbit_misc), - passed. - -disk_monitor_enable(Config) -> - passed = rabbit_ct_broker_helpers:rpc(Config, 0, - ?MODULE, disk_monitor_enable1, [Config]). - -disk_monitor_enable1(_Config) -> - ok = meck:new(rabbit_misc, [passthrough]), - ok = meck:expect(rabbit_misc, os_cmd, fun(_) -> "\n" end), - application:set_env(rabbit, disk_monitor_failure_retries, 20000), - application:set_env(rabbit, disk_monitor_failure_retry_interval, 100), - ok = rabbit_sup:stop_child(rabbit_disk_monitor_sup), - ok = rabbit_sup:start_delayed_restartable_child(rabbit_disk_monitor, [1000]), - undefined = rabbit_disk_monitor:get_disk_free(), - Cmd = case os:type() of - {win32, _} -> " Le volume dans le lecteur C n’a pas de nom.\n" - " Le numéro de série du volume est 707D-5BDC\n" - "\n" - " Répertoire de C:\Users\n" - "\n" - "10/12/2015 11:01 <DIR> .\n" - "10/12/2015 11:01 <DIR> ..\n" - " 0 fichier(s) 0 octets\n" - " 2 Rép(s) 758537121792 octets libres\n"; - _ -> "Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted on\n" - "/dev/disk1 975798272 234783364 740758908 25% 58759839 185189727 24% /\n" - end, - ok = meck:expect(rabbit_misc, os_cmd, fun(_) -> Cmd end), - timer:sleep(1000), - Bytes = 740758908 * 1024, - Bytes = rabbit_disk_monitor:get_disk_free(), - meck:unload(rabbit_misc), - application:set_env(rabbit, disk_monitor_failure_retries, 10), - application:set_env(rabbit, disk_monitor_failure_retry_interval, 120000), - passed. diff --git a/test/unit_disk_monitor_mocks_SUITE.erl b/test/unit_disk_monitor_mocks_SUITE.erl new file mode 100644 index 0000000000..f9deb1de1f --- /dev/null +++ b/test/unit_disk_monitor_mocks_SUITE.erl @@ -0,0 +1,121 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_disk_monitor_mocks_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +-define(TIMEOUT, 30000). + +all() -> + [ + {group, sequential_tests} + ]. + +groups() -> + [ + {sequential_tests, [], [ + disk_monitor, + disk_monitor_enable + ]} + ]. + +%% ------------------------------------------------------------------- +%% Testsuite setup/teardown +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:run_setup_steps(Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +init_per_group(Group, Config) -> + Config1 = rabbit_ct_helpers:set_config(Config, [ + {rmq_nodename_suffix, Group}, + {rmq_nodes_count, 1} + ]), + rabbit_ct_helpers:run_steps(Config1, + rabbit_ct_broker_helpers:setup_steps() ++ + rabbit_ct_client_helpers:setup_steps()). + +end_per_group(_Group, Config) -> + rabbit_ct_helpers:run_steps(Config, + rabbit_ct_client_helpers:teardown_steps() ++ + rabbit_ct_broker_helpers:teardown_steps()). + +init_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_started(Config, Testcase). + +end_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_finished(Config, Testcase). + +%% ------------------------------------------------------------------- +%% Test cases +%% ------------------------------------------------------------------- + +disk_monitor(Config) -> + passed = rabbit_ct_broker_helpers:rpc(Config, 0, + ?MODULE, disk_monitor1, [Config]). + +disk_monitor1(_Config) -> + %% Issue: rabbitmq-server #91 + %% os module could be mocked using 'unstick', however it may have undesired + %% side effects in following tests. Thus, we mock at rabbit_misc level + ok = meck:new(rabbit_misc, [passthrough]), + ok = meck:expect(rabbit_misc, os_cmd, fun(_) -> "\n" end), + ok = rabbit_sup:stop_child(rabbit_disk_monitor_sup), + ok = rabbit_sup:start_delayed_restartable_child(rabbit_disk_monitor, [1000]), + meck:unload(rabbit_misc), + passed. + +disk_monitor_enable(Config) -> + passed = rabbit_ct_broker_helpers:rpc(Config, 0, + ?MODULE, disk_monitor_enable1, [Config]). + +disk_monitor_enable1(_Config) -> + ok = meck:new(rabbit_misc, [passthrough]), + ok = meck:expect(rabbit_misc, os_cmd, fun(_) -> "\n" end), + application:set_env(rabbit, disk_monitor_failure_retries, 20000), + application:set_env(rabbit, disk_monitor_failure_retry_interval, 100), + ok = rabbit_sup:stop_child(rabbit_disk_monitor_sup), + ok = rabbit_sup:start_delayed_restartable_child(rabbit_disk_monitor, [1000]), + undefined = rabbit_disk_monitor:get_disk_free(), + Cmd = case os:type() of + {win32, _} -> " Le volume dans le lecteur C n’a pas de nom.\n" + " Le numéro de série du volume est 707D-5BDC\n" + "\n" + " Répertoire de C:\Users\n" + "\n" + "10/12/2015 11:01 <DIR> .\n" + "10/12/2015 11:01 <DIR> ..\n" + " 0 fichier(s) 0 octets\n" + " 2 Rép(s) 758537121792 octets libres\n"; + _ -> "Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted on\n" + "/dev/disk1 975798272 234783364 740758908 25% 58759839 185189727 24% /\n" + end, + ok = meck:expect(rabbit_misc, os_cmd, fun(_) -> Cmd end), + timer:sleep(1000), + Bytes = 740758908 * 1024, + Bytes = rabbit_disk_monitor:get_disk_free(), + meck:unload(rabbit_misc), + application:set_env(rabbit, disk_monitor_failure_retries, 10), + application:set_env(rabbit, disk_monitor_failure_retry_interval, 120000), + passed. diff --git a/test/unit_gen_server2_SUITE.erl b/test/unit_gen_server2_SUITE.erl new file mode 100644 index 0000000000..0135193ff1 --- /dev/null +++ b/test/unit_gen_server2_SUITE.erl @@ -0,0 +1,79 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_gen_server2_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, sequential_tests} + ]. + +groups() -> + [ + {sequential_tests, [], [ + gen_server2_with_state + ]} + ]. + +%% ------------------------------------------------------------------- +%% Testsuite setup/teardown +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:run_setup_steps(Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +init_per_group(Group, Config) -> + Config1 = rabbit_ct_helpers:set_config(Config, [ + {rmq_nodename_suffix, Group}, + {rmq_nodes_count, 1} + ]), + rabbit_ct_helpers:run_steps(Config1, + rabbit_ct_broker_helpers:setup_steps() ++ + rabbit_ct_client_helpers:setup_steps()). + +end_per_group(_Group, Config) -> + rabbit_ct_helpers:run_steps(Config, + rabbit_ct_client_helpers:teardown_steps() ++ + rabbit_ct_broker_helpers:teardown_steps()). + +init_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_started(Config, Testcase). + +end_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_finished(Config, Testcase). + + +%% ------------------------------------------------------------------- +%% Test cases +%% ------------------------------------------------------------------- + +gen_server2_with_state(Config) -> + passed = rabbit_ct_broker_helpers:rpc(Config, 0, + ?MODULE, gen_server2_with_state1, [Config]). + +gen_server2_with_state1(_Config) -> + fhc_state = gen_server2:with_state(file_handle_cache, + fun (S) -> element(1, S) end), + passed. diff --git a/test/unit_inbroker_parallel_SUITE.erl b/test/unit_inbroker_parallel_SUITE.erl index f0d4b7b1c6..3933c37748 100644 --- a/test/unit_inbroker_parallel_SUITE.erl +++ b/test/unit_inbroker_parallel_SUITE.erl @@ -47,9 +47,7 @@ groups() -> [ {parallel_tests, [parallel], [ configurable_server_properties, - credit_flow_settings, dynamic_mirroring, - gen_server2_with_state, mcall, max_message_size, @@ -464,17 +462,6 @@ test_spawn_remote() -> after ?TIMEOUT -> throw(failed_to_receive_result) end. -%% --------------------------------------------------------------------------- -%% Unordered tests (originally from rabbit_tests.erl). -%% --------------------------------------------------------------------------- -gen_server2_with_state(Config) -> - passed = rabbit_ct_broker_helpers:rpc(Config, 0, - ?MODULE, gen_server2_with_state1, [Config]). - -gen_server2_with_state1(_Config) -> - fhc_state = gen_server2:with_state(file_handle_cache, - fun (S) -> element(1, S) end), - passed. mcall(Config) -> passed = rabbit_ct_broker_helpers:rpc(Config, 0, diff --git a/test/unit_operator_policy_SUITE.erl b/test/unit_operator_policy_SUITE.erl new file mode 100644 index 0000000000..36620aa66c --- /dev/null +++ b/test/unit_operator_policy_SUITE.erl @@ -0,0 +1,122 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_operator_policy_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, parallel_tests} + ]. + +groups() -> + [ + {parallel_tests, [parallel], [ + merge_operator_policy_definitions + ]} + ]. + +init_per_testcase(TC, Config) when TC =:= decrypt_start_app; + TC =:= decrypt_start_app_file; + TC =:= decrypt_start_app_undefined; + TC =:= decrypt_start_app_wrong_passphrase -> + application:set_env(rabbit, feature_flags_file, "", [{persistent, true}]), + Config; +init_per_testcase(_Testcase, Config) -> + Config. + +end_per_testcase(_TC, _Config) -> + ok. + + +%% ------------------------------------------------------------------- +%% Test Cases +%% ------------------------------------------------------------------- + +merge_operator_policy_definitions(_Config) -> + P1 = undefined, + P2 = [{definition, [{<<"message-ttl">>, 3000}]}], + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P1, P2)), + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P2, P1)), + + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P1, rabbit_data_coercion:to_map(P2))), + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(rabbit_data_coercion:to_map(P2), P1)), + + ?assertEqual(undefined, rabbit_policy:merge_operator_definitions(undefined, undefined)), + + ?assertEqual([], rabbit_policy:merge_operator_definitions([], [])), + ?assertEqual([], rabbit_policy:merge_operator_definitions(#{}, [])), + ?assertEqual([], rabbit_policy:merge_operator_definitions(#{}, #{})), + ?assertEqual([], rabbit_policy:merge_operator_definitions([], #{})), + + %% operator policy takes precedence + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions( + [{definition, [ + {<<"message-ttl">>, 5000} + ]}], + [{definition, [ + {<<"message-ttl">>, 3000} + ]}] + )), + + ?assertEqual([{<<"delivery-limit">>, 20}, + {<<"message-ttl">>, 3000}], + rabbit_policy:merge_operator_definitions( + [{definition, [ + {<<"message-ttl">>, 5000}, + {<<"delivery-limit">>, 20} + ]}], + [{definition, [ + {<<"message-ttl">>, 3000} + ]}]) + ), + + ?assertEqual( + [{<<"delivery-limit">>, 20}, + {<<"message-ttl">>, 3000}, + {<<"unknown">>, <<"value">>}], + + rabbit_policy:merge_operator_definitions( + #{definition => #{ + <<"message-ttl">> => 5000, + <<"delivery-limit">> => 20 + }}, + #{definition => #{ + <<"message-ttl">> => 3000, + <<"unknown">> => <<"value">> + }}) + ), + + ?assertEqual( + [{<<"delivery-limit">>, 20}, + {<<"message-ttl">>, 3000}], + + rabbit_policy:merge_operator_definitions( + #{definition => #{ + <<"message-ttl">> => 5000, + <<"delivery-limit">> => 20 + }}, + [{definition, [ + {<<"message-ttl">>, 3000} + ]}]) + ), + + passed. diff --git a/test/unit_plugin_directories_SUITE.erl b/test/unit_plugin_directories_SUITE.erl new file mode 100644 index 0000000000..3a4ae44581 --- /dev/null +++ b/test/unit_plugin_directories_SUITE.erl @@ -0,0 +1,85 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_plugin_directories_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, parallel_tests} + ]. + +groups() -> + [ + {parallel_tests, [parallel], [ + listing_plugins_from_multiple_directories + ]} + ]. + + +%% ------------------------------------------------------------------- +%% Test Cases +%% ------------------------------------------------------------------- + +listing_plugins_from_multiple_directories(Config) -> + %% Generate some fake plugins in .ez files + FirstDir = filename:join([?config(priv_dir, Config), "listing_plugins_from_multiple_directories-1"]), + SecondDir = filename:join([?config(priv_dir, Config), "listing_plugins_from_multiple_directories-2"]), + ok = file:make_dir(FirstDir), + ok = file:make_dir(SecondDir), + lists:foreach(fun({Dir, AppName, Vsn}) -> + EzName = filename:join([Dir, io_lib:format("~s-~s.ez", [AppName, Vsn])]), + AppFileName = lists:flatten(io_lib:format("~s-~s/ebin/~s.app", [AppName, Vsn, AppName])), + AppFileContents = list_to_binary( + io_lib:format( + "~p.", + [{application, AppName, + [{vsn, Vsn}, + {applications, [kernel, stdlib, rabbit]}]}])), + {ok, {_, EzData}} = zip:zip(EzName, [{AppFileName, AppFileContents}], [memory]), + ok = file:write_file(EzName, EzData) + end, + [{FirstDir, plugin_first_dir, "3"}, + {SecondDir, plugin_second_dir, "4"}, + {FirstDir, plugin_both, "1"}, + {SecondDir, plugin_both, "2"}]), + + %% Everything was collected from both directories, plugin with higher + %% version should take precedence + PathSep = case os:type() of + {win32, _} -> ";"; + _ -> ":" + end, + Path = FirstDir ++ PathSep ++ SecondDir, + Got = lists:sort([{Name, Vsn} || #plugin{name = Name, version = Vsn} <- rabbit_plugins:list(Path)]), + %% `rabbit` was loaded automatically by `rabbit_plugins:list/1`. + %% We want to unload it now so it does not interfere with other + %% testcases. + application:unload(rabbit), + Expected = [{plugin_both, "2"}, {plugin_first_dir, "3"}, {plugin_second_dir, "4"}], + case Got of + Expected -> + ok; + _ -> + ct:pal("Got ~p~nExpected: ~p", [Got, Expected]), + exit({wrong_plugins_list, Got}) + end, + ok. diff --git a/test/unit_supervisor2_SUITE.erl b/test/unit_supervisor2_SUITE.erl new file mode 100644 index 0000000000..c1dffe575e --- /dev/null +++ b/test/unit_supervisor2_SUITE.erl @@ -0,0 +1,78 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2020 VMware, Inc. or its affiliates. All rights reserved. +%% + +-module(unit_supervisor2_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, sequential_tests} + ]. + +groups() -> + [ + {sequential_tests, [], [ + check_shutdown_stop, + check_shutdown_ignored + ]} + ]. + +%% ------------------------------------------------------------------- +%% Test Cases +%% ------------------------------------------------------------------- + +check_shutdown_stop(_Config) -> + ok = check_shutdown(stop, 200, 200, 2000). + +check_shutdown_ignored(_Config) -> + ok = check_shutdown(ignored, 1, 2, 2000). + +check_shutdown(SigStop, Iterations, ChildCount, SupTimeout) -> + {ok, Sup} = supervisor2:start_link(dummy_supervisor2, [SupTimeout]), + Res = lists:foldl( + fun (I, ok) -> + TestSupPid = erlang:whereis(dummy_supervisor2), + ChildPids = + [begin + {ok, ChildPid} = + supervisor2:start_child(TestSupPid, []), + ChildPid + end || _ <- lists:seq(1, ChildCount)], + MRef = erlang:monitor(process, TestSupPid), + [P ! SigStop || P <- ChildPids], + ok = supervisor2:terminate_child(Sup, test_sup), + {ok, _} = supervisor2:restart_child(Sup, test_sup), + receive + {'DOWN', MRef, process, TestSupPid, shutdown} -> + ok; + {'DOWN', MRef, process, TestSupPid, Reason} -> + {error, {I, Reason}} + end; + (_, R) -> + R + end, ok, lists:seq(1, Iterations)), + unlink(Sup), + MSupRef = erlang:monitor(process, Sup), + exit(Sup, shutdown), + receive + {'DOWN', MSupRef, process, Sup, _Reason} -> + ok + end, + Res. |
