1: %%============================================================================== 2: %% Copyright 2019 Erlang Solutions Ltd. 3: %% 4: %% Licensed under the Apache License, Version 2.0 (the "License"); 5: %% you may not use this file except in compliance with the License. 6: %% You may obtain a copy of the License at 7: %% 8: %% http://www.apache.org/licenses/LICENSE-2.0 9: %% 10: %% Unless required by applicable law or agreed to in writing, software 11: %% distributed under the License is distributed on an "AS IS" BASIS, 12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13: %% See the License for the specific language governing permissions and 14: %% limitations under the License. 15: %%============================================================================== 16: 17: -module(pubsub_backend_SUITE). 18: -compile([export_all, nowarn_export_all]). 19: -author('michael.uvarov@erlang-solutions.com'). 20: 21: -include_lib("common_test/include/ct.hrl"). 22: -include_lib("exml/include/exml.hrl"). 23: -include("mongoose.hrl"). 24: -include("jlib.hrl"). 25: -include("pubsub.hrl"). 26: 27: %%-------------------------------------------------------------------- 28: %% Suite configuration 29: %%-------------------------------------------------------------------- 30: 31: all() -> 32: [{group, tree_handling}]. 33: 34: groups() -> 35: [ 36: {tree_handling, [], tree_handling_tests()} 37: ]. 38: 39: tree_handling_tests() -> 40: [ 41: get_subnodes_case 42: ]. 43: 44: suite() -> 45: []. 46: 47: %%-------------------------------------------------------------------- 48: %% Init & teardown 49: %%-------------------------------------------------------------------- 50: 51: init_per_suite(Config) -> 52: ok = mnesia:create_schema([node()]), 53: mnesia:start(), 54: mod_pubsub_db_mnesia:init(global, #{}), 55: {ok, _} = application:ensure_all_started(jid), 56: Config. 57: 58: end_per_suite(Config) -> 59: mod_pubsub_db_mnesia:stop(), 60: mnesia:stop(), 61: mnesia:delete_schema([node()]), 62: Config. 63: 64: init_per_group(_GroupName, Config) -> 65: Config. 66: 67: end_per_group(_GroupName, Config) -> 68: Config. 69: 70: init_per_testcase(_CaseName, Config) -> 71: Config. 72: 73: end_per_testcase(_CaseName, Config) -> 74: Config. 75: 76: %%-------------------------------------------------------------------- 77: %% Tree handling tests 78: %%-------------------------------------------------------------------- 79: 80: get_subnodes_case(_Config) -> 81: mod_pubsub_db_mnesia:transaction(fun() -> 82: get_subnodes_case_tr() 83: end, #{}). 84: 85: get_subnodes_case_tr() -> 86: create_jojo_tree(), 87: %% Get "root"-kinda nodes 88: compare_lists(people_with_both_parents_unknown(), nodes_to_names(get_subnodes(<<>>))), 89: %% Joseph has two children 90: compare_lists([<<"Josuke Higashikata">>, <<"Holy Kujo">>], 91: nodes_to_names(get_subnodes(<<"Joseph Joestar">>))), 92: %% Jotaro is a son of Holy 93: compare_lists([<<"Jotaro Kujo">>], 94: nodes_to_names(get_subnodes(<<"Holy Kujo">>))), 95: 96: HolyDescendants = get_subnodes_tree(<<"Holy Kujo">>), 97: HolyAncestors = get_parentnodes_tree(<<"Holy Kujo">>), 98: 99: %% level 0 is the last item 100: {0, _} = lists:last(HolyDescendants), 101: {0, _} = lists:last(HolyAncestors), 102: 103: %% Level 0 contains the node itself 104: compare_lists([<<"Holy Kujo">>], nodes_to_names(proplists:get_value(0, HolyDescendants))), 105: compare_lists([<<"Jotaro Kujo">>], nodes_to_names(proplists:get_value(1, HolyDescendants))), 106: compare_lists([<<"Jolyne Cujoh">>], nodes_to_names(proplists:get_value(2, HolyDescendants))), 107: compare_lists([], nodes_to_names(proplists:get_value(3, HolyDescendants))), 108: undefined = proplists:get_value(4, HolyDescendants), %% No such item on depth 4 109: 110: compare_lists([<<"Holy Kujo">>], nodes_to_names(proplists:get_value(0, HolyAncestors))), 111: compare_lists([<<"Joseph Joestar">>, <<"Suzi Q Joestar">>], nodes_to_names(proplists:get_value(1, HolyAncestors))), 112: compare_lists([<<"George Joestar II">>, <<"Elizabeth Joestar">>], nodes_to_names(proplists:get_value(2, HolyAncestors))), 113: compare_lists([<<"Erina Joestar">>, <<"Jonathan Joestar">>], nodes_to_names(proplists:get_value(3, HolyAncestors))), 114: compare_lists([<<"George Joestar I">>, <<"Mary Joestar">>], nodes_to_names(proplists:get_value(4, HolyAncestors))), 115: undefined = proplists:get_value(5, HolyAncestors), 116: 117: %% Dio not found 118: [] = get_subnodes(<<"Dio">>), 119: [ {1, []}, {0, [false]} ] = get_subnodes_tree(<<"Dio">>), 120: [ {0, []} ] = get_parentnodes_tree(<<"Dio">>), 121: ok. 122: 123: 124: %%-------------------------------------------------------------------- 125: %% Helpers 126: %%-------------------------------------------------------------------- 127: 128: make_node(Name, Parents) -> 129: #pubsub_node{nodeid = {host(), Name}, parents = Parents}. 130: 131: host() -> 132: <<"localhost">>. 133: 134: set_node(N) -> 135: mod_pubsub_db_mnesia:set_node(N). 136: 137: get_subnodes(Name) -> 138: mod_pubsub_db_mnesia:get_subnodes(host(), Name). 139: 140: get_subnodes_tree(Name) -> 141: mod_pubsub_db_mnesia:get_subnodes_tree(host(), Name). 142: 143: get_parentnodes_tree(Name) -> 144: mod_pubsub_db_mnesia:get_parentnodes_tree(host(), Name). 145: 146: %% https://jojo.fandom.com/wiki/Joestar_Family 147: create_jojo_tree() -> 148: set_node(make_node(<<"George Joestar I">>, [])), 149: set_node(make_node(<<"Mary Joestar">>, [])), 150: 151: set_node(make_node(<<"Jonathan Joestar">>, 152: [<<"George Joestar I">>, <<"Mary Joestar">>])), 153: set_node(make_node(<<"Erina Joestar">>, [])), 154: 155: set_node(make_node(<<"George Joestar II">>, 156: [<<"Jonathan Joestar">>, <<"Erina Joestar">>])), 157: set_node(make_node(<<"Elizabeth Joestar">>, [])), 158: 159: set_node(make_node(<<"Joseph Joestar">>, 160: [<<"George Joestar II">>, <<"Elizabeth Joestar">>])), 161: set_node(make_node(<<"Tomoko Higashikata">>, [])), 162: set_node(make_node(<<"Suzi Q Joestar">>, [])), 163: 164: set_node(make_node(<<"Josuke Higashikata">>, 165: [<<"Tomoko Higashikata">>, <<"Joseph Joestar">>])), 166: set_node(make_node(<<"Holy Kujo">>, 167: [<<"Joseph Joestar">>, <<"Suzi Q Joestar">>])), 168: 169: set_node(make_node(<<"Sadao Kujo">>, [])), 170: 171: set_node(make_node(<<"Jotaro Kujo">>, 172: [<<"Holy Kujo">>, <<"Sadao Kujo">>])), 173: 174: set_node(make_node(<<"Jolyne Cujoh">>, [<<"Jotaro Kujo">>])), 175: ok. 176: 177: nodes_to_names(Nodes) -> 178: [node_to_name(N) || N <- Nodes]. 179: 180: node_to_name(#pubsub_node{nodeid = {_, Name}}) -> 181: Name. 182: 183: people_with_both_parents_unknown() -> 184: [<<"Elizabeth Joestar">>, 185: <<"Erina Joestar">>, 186: <<"George Joestar I">>, 187: <<"Mary Joestar">>, 188: <<"Sadao Kujo">>, 189: <<"Suzi Q Joestar">>, 190: <<"Tomoko Higashikata">>]. 191: 192: %% Compare lists ignoring order 193: compare_lists(L1, L2) -> 194: SL1 = lists:sort(L1), 195: SL2 = lists:sort(L2), 196: case SL1 of 197: SL2 -> 198: ok; 199: _ -> 200: ct:fail({compare_lists, {expected, SL1}, {provided, SL2}}) 201: end.