|
| 1 | +%% This Source Code Form is subject to the terms of the Mozilla Public |
| 2 | +%% License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 | +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| 4 | +%% |
| 5 | +%% Copyright (c) 2011-2023 VMware, Inc. or its affiliates. All rights reserved. |
| 6 | +%% |
| 7 | + |
| 8 | +-module(routing_SUITE). |
| 9 | + |
| 10 | +-include_lib("eunit/include/eunit.hrl"). |
| 11 | +-include_lib("amqp_client/include/amqp_client.hrl"). |
| 12 | +-include_lib("common_test/include/ct.hrl"). |
| 13 | + |
| 14 | +-compile([nowarn_export_all, export_all]). |
| 15 | +-compile(export_all). |
| 16 | + |
| 17 | +-define(VHOST, <<"/">>). |
| 18 | +-define(USER, <<"user">>). |
| 19 | + |
| 20 | +all() -> |
| 21 | + [ |
| 22 | + {group, mnesia_store} |
| 23 | + ]. |
| 24 | + |
| 25 | +suite() -> |
| 26 | + [{timetrap, {minutes, 5}}]. |
| 27 | + |
| 28 | +groups() -> |
| 29 | + [ |
| 30 | + {mnesia_store, [], all_tests()} |
| 31 | + ]. |
| 32 | + |
| 33 | +all_tests() -> |
| 34 | + [ |
| 35 | + topic |
| 36 | + ]. |
| 37 | + |
| 38 | +%% ------------------------------------------------------------------- |
| 39 | +%% Test suite setup/teardown. |
| 40 | +%% ------------------------------------------------------------------- |
| 41 | + |
| 42 | +init_per_suite(Config) -> |
| 43 | + rabbit_ct_helpers:log_environment(), |
| 44 | + rabbit_ct_helpers:run_setup_steps(Config). |
| 45 | + |
| 46 | +end_per_suite(Config) -> |
| 47 | + rabbit_ct_helpers:run_teardown_steps(Config). |
| 48 | + |
| 49 | +init_per_group(mnesia_store = Group, Config) -> |
| 50 | + Config1 = rabbit_ct_helpers:set_config(Config, [ |
| 51 | + {rmq_nodename_suffix, Group}, |
| 52 | + {rmq_nodes_count, 1} |
| 53 | + ]), |
| 54 | + rabbit_ct_helpers:run_steps(Config1, |
| 55 | + rabbit_ct_broker_helpers:setup_steps() ++ |
| 56 | + rabbit_ct_client_helpers:setup_steps()). |
| 57 | + |
| 58 | +end_per_group(_Group, Config) -> |
| 59 | + rabbit_ct_helpers:run_steps(Config, |
| 60 | + rabbit_ct_client_helpers:teardown_steps() ++ |
| 61 | + rabbit_ct_broker_helpers:teardown_steps()). |
| 62 | + |
| 63 | +init_per_testcase(Testcase, Config) -> |
| 64 | + rabbit_ct_helpers:testcase_started(Config, Testcase). |
| 65 | + |
| 66 | +end_per_testcase(Testcase, Config) -> |
| 67 | + rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_db_binding, clear, []), |
| 68 | + rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_db_exchange, clear, []), |
| 69 | + rabbit_ct_helpers:testcase_finished(Config, Testcase). |
| 70 | + |
| 71 | +%% --------------------------------------------------------------------------- |
| 72 | +%% Test Cases |
| 73 | +%% --------------------------------------------------------------------------- |
| 74 | + |
| 75 | +topic(Config) -> |
| 76 | + passed = rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, topic1, [Config]). |
| 77 | + |
| 78 | +topic1(_Config) -> |
| 79 | + XName = rabbit_misc:r(?VHOST, exchange, <<"topic_matching-exchange">>), |
| 80 | + X = rabbit_exchange:declare( |
| 81 | + XName, topic, _Durable = true, _AutoDelete = false, |
| 82 | + _Internal = false, _Args = [], ?USER), |
| 83 | + |
| 84 | + %% add some bindings |
| 85 | + Bindings = [#binding{source = XName, |
| 86 | + key = list_to_binary(Key), |
| 87 | + destination = rabbit_misc:r( |
| 88 | + ?VHOST, queue, list_to_binary(Q)), |
| 89 | + args = Args} || |
| 90 | + {Key, Q, Args} <- [{"a.b.c", "t1", []}, |
| 91 | + {"a.*.c", "t2", []}, |
| 92 | + {"a.#.b", "t3", []}, |
| 93 | + {"a.b.b.c", "t4", []}, |
| 94 | + {"#", "t5", []}, |
| 95 | + {"#.#", "t6", []}, |
| 96 | + {"#.b", "t7", []}, |
| 97 | + {"*.*", "t8", []}, |
| 98 | + {"a.*", "t9", []}, |
| 99 | + {"*.b.c", "t10", []}, |
| 100 | + {"a.#", "t11", []}, |
| 101 | + {"a.#.#", "t12", []}, |
| 102 | + {"b.b.c", "t13", []}, |
| 103 | + {"a.b.b", "t14", []}, |
| 104 | + {"a.b", "t15", []}, |
| 105 | + {"b.c", "t16", []}, |
| 106 | + {"", "t17", []}, |
| 107 | + {"*.*.*", "t18", []}, |
| 108 | + {"vodka.martini", "t19", []}, |
| 109 | + {"a.b.c", "t20", []}, |
| 110 | + {"*.#", "t21", []}, |
| 111 | + {"#.*.#", "t22", []}, |
| 112 | + {"*.#.#", "t23", []}, |
| 113 | + {"#.#.#", "t24", []}, |
| 114 | + {"*", "t25", []}, |
| 115 | + {"#.b.#", "t26", []}, |
| 116 | + {"args-test", "t27", |
| 117 | + [{<<"foo">>, longstr, <<"bar">>}]}, |
| 118 | + {"args-test", "t27", %% Note aliasing |
| 119 | + [{<<"foo">>, longstr, <<"baz">>}]}]], |
| 120 | + [ok = create_binding(Binding) || Binding <- Bindings], |
| 121 | + |
| 122 | + test_topic_expect_match( |
| 123 | + X, [{"a.b.c", ["t1", "t2", "t5", "t6", "t10", "t11", "t12", |
| 124 | + "t18", "t20", "t21", "t22", "t23", "t24", |
| 125 | + "t26"]}, |
| 126 | + {"a.b", ["t3", "t5", "t6", "t7", "t8", "t9", "t11", |
| 127 | + "t12", "t15", "t21", "t22", "t23", "t24", |
| 128 | + "t26"]}, |
| 129 | + {"a.b.b", ["t3", "t5", "t6", "t7", "t11", "t12", "t14", |
| 130 | + "t18", "t21", "t22", "t23", "t24", "t26"]}, |
| 131 | + {"", ["t5", "t6", "t17", "t24"]}, |
| 132 | + {"b.c.c", ["t5", "t6", "t18", "t21", "t22", "t23", |
| 133 | + "t24", "t26"]}, |
| 134 | + {"a.a.a.a.a", ["t5", "t6", "t11", "t12", "t21", "t22", |
| 135 | + "t23", "t24"]}, |
| 136 | + {"vodka.gin", ["t5", "t6", "t8", "t21", "t22", "t23", |
| 137 | + "t24"]}, |
| 138 | + {"vodka.martini", ["t5", "t6", "t8", "t19", "t21", "t22", "t23", |
| 139 | + "t24"]}, |
| 140 | + {"b.b.c", ["t5", "t6", "t10", "t13", "t18", "t21", |
| 141 | + "t22", "t23", "t24", "t26"]}, |
| 142 | + {"nothing.here.at.all", ["t5", "t6", "t21", "t22", "t23", "t24"]}, |
| 143 | + {"oneword", ["t5", "t6", "t21", "t22", "t23", "t24", |
| 144 | + "t25"]}, |
| 145 | + {"args-test", ["t5", "t6", "t21", "t22", "t23", "t24", |
| 146 | + "t25", "t27"]}]), |
| 147 | + |
| 148 | + %% remove some bindings |
| 149 | + RemovedBindings = [lists:nth(N, Bindings) || N <- [1, 5, 11, 19, 21, 28]], |
| 150 | + [delete_binding(Binding) || Binding <- RemovedBindings], |
| 151 | + |
| 152 | + %% test some matches |
| 153 | + test_topic_expect_match( |
| 154 | + X, |
| 155 | + [{"a.b.c", ["t2", "t6", "t10", "t12", "t18", "t20", "t22", |
| 156 | + "t23", "t24", "t26"]}, |
| 157 | + {"a.b", ["t3", "t6", "t7", "t8", "t9", "t12", "t15", |
| 158 | + "t22", "t23", "t24", "t26"]}, |
| 159 | + {"a.b.b", ["t3", "t6", "t7", "t12", "t14", "t18", "t22", |
| 160 | + "t23", "t24", "t26"]}, |
| 161 | + {"", ["t6", "t17", "t24"]}, |
| 162 | + {"b.c.c", ["t6", "t18", "t22", "t23", "t24", "t26"]}, |
| 163 | + {"a.a.a.a.a", ["t6", "t12", "t22", "t23", "t24"]}, |
| 164 | + {"vodka.gin", ["t6", "t8", "t22", "t23", "t24"]}, |
| 165 | + {"vodka.martini", ["t6", "t8", "t22", "t23", "t24"]}, |
| 166 | + {"b.b.c", ["t6", "t10", "t13", "t18", "t22", "t23", |
| 167 | + "t24", "t26"]}, |
| 168 | + {"nothing.here.at.all", ["t6", "t22", "t23", "t24"]}, |
| 169 | + {"oneword", ["t6", "t22", "t23", "t24", "t25"]}, |
| 170 | + {"args-test", ["t6", "t22", "t23", "t24", "t25", "t27"]}]), |
| 171 | + |
| 172 | + %% remove the entire exchange |
| 173 | + rabbit_exchange:delete(XName, _IfUnused = false, ?USER), |
| 174 | + %% none should match now |
| 175 | + test_topic_expect_match(X, [{"a.b.c", []}, {"b.b.c", []}, {"", []}]), |
| 176 | + passed. |
| 177 | + |
| 178 | +%% Internal functions. |
| 179 | + |
| 180 | +%% Create a binding, creating the queue if it does not already exist. |
| 181 | +create_binding(#binding{destination = QName} = Binding) -> |
| 182 | + case rabbit_amqqueue:declare(QName, true, false, [], self(), ?USER) of |
| 183 | + {new, _Q} -> |
| 184 | + ok; |
| 185 | + {existing, _Q} -> |
| 186 | + ok |
| 187 | + end, |
| 188 | + ok = rabbit_binding:add(Binding, ?USER). |
| 189 | + |
| 190 | +delete_binding(Binding) -> |
| 191 | + ok = rabbit_binding:remove(Binding, ?USER). |
| 192 | + |
| 193 | +test_topic_expect_match(X, List) -> |
| 194 | + lists:foreach( |
| 195 | + fun ({Key, Expected}) -> |
| 196 | + BinKey = list_to_binary(Key), |
| 197 | + Message = rabbit_basic:message(X#exchange.name, BinKey, |
| 198 | + #'P_basic'{}, <<>>), |
| 199 | + Msg = mc_amqpl:message(X#exchange.name, |
| 200 | + BinKey, |
| 201 | + Message#basic_message.content), |
| 202 | + Res = rabbit_exchange_type_topic:route(X, Msg), |
| 203 | + ExpectedRes = [rabbit_misc:r(?VHOST, queue, list_to_binary(Q)) || |
| 204 | + Q <- Expected], |
| 205 | + ?assertEqual( |
| 206 | + lists:usort(ExpectedRes), lists:usort(Res), |
| 207 | + lists:flatten(io_lib:format("Routing key: ~p", [BinKey]))) |
| 208 | + end, List). |
0 commit comments