1: -module(config_parser_SUITE). 2: -compile([export_all, nowarn_export_all]). 3: 4: -include_lib("eunit/include/eunit.hrl"). 5: 6: -define(HOST, <<"example.com">>). 7: 8: -define(eq(Expected, Actual), ?assertEqual(Expected, Actual)). 9: 10: %% Assertions 11: 12: %% global config options 13: -define(cfg(Key, Value, RawConfig), ?cfg([{Key, Value}], RawConfig)). 14: -define(cfg(ExpectedOpts, RawConfig), assert_options(ExpectedOpts, parse(RawConfig))). 15: 16: %% global config error 17: -define(err(RawConfig), ?err(_, RawConfig)). 18: -define(err(Pattern, RawConfig), ?assertError({config_error, _, Pattern}, parse(RawConfig))). 19: 20: %% host-or-global config options 21: -define(cfgh(KeyPrefix, Value, RawConfig), ?cfgh([{KeyPrefix, Value}], RawConfig)). 22: -define(cfgh(ExpectedOpts, RawConfig), 23: begin 24: ?cfg(host_opts(ExpectedOpts), RawConfig), 25: ?cfg(host_opts(ExpectedOpts), host_config(RawConfig)) 26: end). 27: 28: %% host-or-global config error 29: -define(errh(RawConfig), ?errh(_, RawConfig)). 30: -define(errh(Pattern, RawConfig), 31: begin 32: ?err(Pattern, RawConfig), 33: ?err(Pattern, host_config(RawConfig)) 34: end). 35: 36: -import(mongoose_config_parser_toml, [extract_errors/1]). 37: -import(config_parser_helper, [merge_with_default_pool_config/1, default_s2s/0, 38: extra_service_listener_config/0, 39: mod_event_pusher_http_handler/0, 40: mod_config/2, default_mod_config/1, 41: config/2, default_config/1]). 42: 43: -type key_prefix() :: top_level_key_prefix() | key_path_prefix(). 44: -type top_level_key_prefix() :: atom(). 45: -type key_path_prefix() :: [atom() | binary()]. 46: 47: all() -> 48: [{group, file}, 49: {group, dynamic_domains}, 50: {group, general}, 51: {group, listen}, 52: {group, auth}, 53: {group, pool}, 54: {group, shaper_acl_access}, 55: {group, s2s}, 56: {group, modules}, 57: {group, services}]. 58: 59: groups() -> 60: [{file, [parallel], [sample_pgsql, 61: miscellaneous, 62: s2s, 63: modules, 64: outgoing_pools, 65: host_types_file]}, 66: {dynamic_domains, [parallel], [supported_features, 67: unsupported_features]}, 68: {general, [parallel], [loglevel, 69: hosts, 70: host_types, 71: default_server_domain, 72: registration_timeout, 73: language, 74: all_metrics_are_global, 75: sm_backend, 76: max_fsm_queue, 77: http_server_name, 78: rdbms_server_type, 79: route_subdomains, 80: mongooseimctl_access_commands, 81: routing_modules, 82: replaced_wait_timeout, 83: hide_service_name, 84: domain_certfile]}, 85: {listen, [parallel], [listen_duplicate, 86: listen_c2s, 87: listen_c2s_fast_tls, 88: listen_c2s_just_tls, 89: listen_s2s, 90: listen_s2s_tls, 91: listen_service, 92: listen_http, 93: listen_http_tls, 94: listen_http_transport, 95: listen_http_handlers_invalid, 96: listen_http_handlers_bosh, 97: listen_http_handlers_websockets, 98: listen_http_handlers_client_api, 99: listen_http_handlers_api, 100: listen_http_handlers_api_admin, 101: listen_http_handlers_api_client, 102: listen_http_handlers_domain]}, 103: {auth, [parallel], [auth_methods, 104: auth_password, 105: auth_sasl_external, 106: auth_allow_multiple_connections, 107: auth_anonymous_protocol, 108: auth_sasl_mechanisms, 109: auth_ldap_pool, 110: auth_ldap_bind_pool, 111: auth_ldap_base, 112: auth_ldap_uids, 113: auth_ldap_filter, 114: auth_ldap_dn_filter, 115: auth_ldap_local_filter, 116: auth_ldap_deref, 117: auth_external, 118: auth_http_basic_auth, 119: auth_jwt, 120: auth_riak_bucket_type, 121: auth_rdbms_users_number_estimate, 122: auth_dummy]}, 123: {pool, [parallel], [pool_type, 124: pool_tag, 125: pool_scope, 126: pool_workers, 127: pool_strategy, 128: pool_call_timeout, 129: pool_rdbms_settings, 130: pool_rdbms_keepalive_interval, 131: pool_rdbms_server, 132: pool_rdbms_port, 133: pool_rdbms_tls, 134: pool_http_host, 135: pool_http_path_prefix, 136: pool_http_request_timeout, 137: pool_http_tls, 138: pool_redis_host, 139: pool_redis_port, 140: pool_redis_database, 141: pool_redis_password, 142: pool_riak_address, 143: pool_riak_port, 144: pool_riak_credentials, 145: pool_riak_cacertfile, 146: pool_riak_tls, 147: pool_cassandra_servers, 148: pool_cassandra_keyspace, 149: pool_cassandra_auth, 150: pool_cassandra_tls, 151: pool_ldap_port, 152: pool_ldap_servers, 153: pool_ldap_encrypt, 154: pool_ldap_rootdn, 155: pool_ldap_password, 156: pool_ldap_connect_interval, 157: pool_ldap_tls]}, 158: {shaper_acl_access, [parallel], [shaper, 159: acl, 160: acl_merge_host_and_global, 161: access, 162: access_merge_host_and_global]}, 163: {s2s, [parallel], [s2s_host_config, 164: s2s_dns_timeout, 165: s2s_dns_retries, 166: s2s_outgoing_port, 167: s2s_outgoing_ip_versions, 168: s2s_outgoing_timeout, 169: s2s_use_starttls, 170: s2s_certfile, 171: s2s_default_policy, 172: s2s_host_policy, 173: s2s_address, 174: s2s_ciphers, 175: s2s_shared, 176: s2s_max_retry_delay]}, 177: {modules, [parallel], [mod_adhoc, 178: mod_auth_token, 179: mod_blocking, 180: mod_bosh, 181: mod_caps, 182: mod_cache_users, 183: mod_carboncopy, 184: mod_csi, 185: mod_disco, 186: mod_inbox, 187: mod_global_distrib, 188: mod_global_distrib_connections, 189: mod_global_distrib_connections_endpoints, 190: mod_global_distrib_connections_advertised_endpoints, 191: mod_global_distrib_connections_tls, 192: mod_global_distrib_redis, 193: mod_global_distrib_cache, 194: mod_global_distrib_bounce, 195: mod_event_pusher_sns, 196: mod_event_pusher_push, 197: mod_event_pusher_http, 198: mod_event_pusher_rabbit, 199: mod_extdisco, 200: mod_http_upload, 201: mod_http_upload_s3, 202: mod_jingle_sip, 203: mod_keystore, 204: mod_keystore_keys, 205: mod_last, 206: mod_mam_meta, 207: mod_mam_meta_riak, 208: mod_mam_meta_pm, 209: mod_mam_meta_muc, 210: mod_muc, 211: mod_muc_default_room, 212: mod_muc_default_room_affiliations, 213: mod_muc_log, 214: mod_muc_log_top_link, 215: mod_muc_light, 216: mod_muc_light_config_schema, 217: mod_offline, 218: mod_offline_chatmarkers, 219: mod_ping, 220: mod_privacy, 221: mod_private, 222: mod_pubsub, 223: mod_pubsub_pep_mapping, 224: mod_pubsub_default_node_config, 225: mod_push_service_mongoosepush, 226: mod_register, 227: mod_roster, 228: mod_shared_roster_ldap, 229: mod_sic, 230: mod_smart_markers, 231: mod_stream_management, 232: mod_stream_management_stale_h, 233: mod_time, 234: mod_vcard, 235: mod_vcard_ldap_uids, 236: mod_vcard_ldap_vcard_map, 237: mod_vcard_ldap_search_fields, 238: mod_vcard_ldap_search_reported, 239: mod_version, 240: modules_without_config, 241: incorrect_module]}, 242: {services, [parallel], [service_admin_extra, 243: service_domain_db, 244: service_mongoose_system_metrics]} 245: ]. 246: 247: init_per_suite(Config) -> 248: {ok, _} = application:ensure_all_started(jid), 249: create_files(Config), 250: Config. 251: 252: end_per_suite(_Config) -> 253: ok. 254: 255: init_per_group(dynamic_domains, Config) -> 256: meck:new(ejabberd_auth_http, [passthrough, no_link]), 257: meck:new(mod_test, [non_strict, no_link]), 258: meck:expect(ejabberd_auth_http, supported_features, fun() -> [] end), 259: meck:expect(mod_test, supported_features, fun() -> [] end), 260: Config; 261: init_per_group(_, Config) -> 262: Config. 263: 264: end_per_group(dynamic_domains, _Config) -> 265: meck:unload(); 266: end_per_group(_, _Config) -> 267: ok. 268: 269: init_per_testcase(_, Config) -> 270: Config. 271: 272: end_per_testcase(_, _Config) -> 273: ok. 274: 275: sample_pgsql(Config) -> 276: test_config_file(Config, "mongooseim-pgsql"). 277: 278: miscellaneous(Config) -> 279: test_config_file(Config, "miscellaneous"). 280: 281: s2s(Config) -> 282: test_config_file(Config, "s2s_only"). 283: 284: modules(Config) -> 285: test_config_file(Config, "modules"). 286: 287: outgoing_pools(Config) -> 288: test_config_file(Config, "outgoing_pools"). 289: 290: host_types_file(Config) -> 291: test_config_file(Config, "host_types"). 292: 293: supported_features(_Config) -> 294: Gen = #{<<"general">> => #{<<"host_types">> => [<<"type1">>, <<"type2">>]}}, 295: Auth = #{<<"auth">> => #{<<"internal">> => #{}}}, 296: Mod = #{<<"modules">> => #{<<"mod_amp">> => #{}}}, 297: ?cfg([{auth, <<"type1">>}, methods], [internal], maps:merge(Gen, Auth)), 298: ?cfg([{auth, <<"type1">>}, methods], [internal], 299: Gen#{<<"host_config">> => [Auth#{<<"host_type">> => <<"type1">>}]}), 300: ?cfg([{modules, <<"type1">>}, mod_amp], #{}, maps:merge(Gen, Mod)), 301: ?cfg([{modules, <<"type1">>}, mod_amp], #{}, 302: Gen#{<<"host_config">> => [Mod#{<<"host_type">> => <<"type1">>}]}). 303: 304: unsupported_features(_Config) -> 305: % ejabberd_auth_http and mod_test are mocked and they don't support dynamic domains 306: Gen = #{<<"general">> => #{<<"host_types">> => [<<"type1">>, <<"type2">>]}}, 307: Auth = #{<<"auth">> => #{<<"http">> => #{}}}, 308: Mod = #{<<"modules">> => #{<<"mod_test">> => #{}}}, 309: ?err([#{reason := dynamic_domains_not_supported, 310: unsupported_auth_methods := [http], 311: unsupported_modules := []}], 312: maps:merge(Gen, Auth)), 313: ?err([#{reason := dynamic_domains_not_supported, 314: unsupported_auth_methods := [http], 315: unsupported_modules := []}], 316: Gen#{<<"host_config">> => [Auth#{<<"host_type">> => <<"type1">>}]}), 317: ?err([#{reason := dynamic_domains_not_supported, 318: unsupported_auth_methods := [], 319: unsupported_modules := [mod_test]}], 320: maps:merge(Gen, Mod)), 321: ?err([#{reason := dynamic_domains_not_supported, 322: unsupported_auth_methods := [], 323: unsupported_modules := [mod_test]}], 324: Gen#{<<"host_config">> => [Mod#{<<"host_type">> => <<"type1">>}]}). 325: 326: %% tests: general 327: loglevel(_Config) -> 328: ?cfg(loglevel, warning, #{}), % default 329: ?cfg(loglevel, debug, #{<<"general">> => #{<<"loglevel">> => <<"debug">>}}), 330: ?err(#{<<"general">> => #{<<"loglevel">> => <<"bebug">>}}), 331: %% make sure non-host options are not accepted in host_config 332: ?err(host_config(#{<<"general">> => #{<<"loglevel">> => <<"debug">>}})). 333: 334: hosts(_Config) -> 335: ?cfg(hosts, [], % default 336: #{<<"general">> => #{<<"host_types">> => [<<"type1">>]}, without => [<<"hosts">>]}), 337: ?cfg(hosts, [<<"host1">>], 338: #{<<"general">> => #{<<"hosts">> => [<<"host1">>]}}), 339: ?cfg(hosts, [<<"host1">>, <<"host2">>], 340: #{<<"general">> => #{<<"hosts">> => [<<"host1">>, <<"host2">>]}}), 341: ?err(#{<<"general">> => #{<<"hosts">> => [<<"what is this?">>]}}), 342: ?err(#{<<"general">> => #{<<"hosts">> => [<<>>]}}), 343: ?err(#{<<"general">> => #{<<"hosts">> => [<<"host1">>, <<"host1">>]}}), 344: %% at least one host or host_type must be provided 345: ?err(#{<<"general">> => #{}, without => [<<"hosts">>]}), 346: ?err(#{<<"general">> => #{<<"hosts">> => []}}), 347: ?err(#{<<"general">> => #{<<"host_types">> => []}, without => [<<"hosts">>]}), 348: ?err(#{<<"general">> => #{<<"hosts">> => [], <<"host_types">> => []}}). 349: 350: host_types(_Config) -> 351: ?cfg(host_types, [], #{}), % default 352: ?cfg([{host_types, [<<"type 1">>]}, 353: {hosts, []}], 354: #{<<"general">> => #{<<"host_types">> => [<<"type 1">>]}, without => [<<"hosts">>]}), 355: ?cfg([{host_types, [<<"type 1">>, <<"type 2">>]}, 356: {hosts, []}], 357: #{<<"general">> => #{<<"host_types">> => [<<"type 1">>, <<"type 2">>], 358: <<"hosts">> => []}}), 359: ?err(#{<<"general">> => #{<<"host_types">> => [<<>>]}}), 360: ?err(#{<<"general">> => #{<<"host_types">> => [<<"type1">>, <<"type1">>]}}), 361: %% either hosts and host_types cannot have the same values 362: ?err(#{<<"general">> => #{<<"host_types">> => [<<"type1">>], 363: <<"hosts">> => [<<"type1">>]}}). 364: 365: default_server_domain(_Config) -> 366: ?cfg(default_server_domain, <<"host1">>, 367: #{<<"general">> => #{<<"default_server_domain">> => <<"host1">>}}), 368: ?err(#{<<"general">> => #{<<"default_server_domain">> => <<"what is this?">>}}), 369: ?err(#{<<"general">> => #{<<"default_server_domain">> => <<>>}}), 370: %% default_server_domain must be provided 371: ?err(#{without => [<<"default_server_domain">>]}). 372: 373: registration_timeout(_Config) -> 374: ?cfg(registration_timeout, 600, #{}), % default 375: ?cfg(registration_timeout, infinity, 376: #{<<"general">> => #{<<"registration_timeout">> => <<"infinity">>}}), 377: ?cfg(registration_timeout, 300, 378: #{<<"general">> => #{<<"registration_timeout">> => 300}}), 379: ?err(#{<<"general">> => #{<<"registration_timeout">> => 0}}). 380: 381: language(_Config) -> 382: ?cfg(language, <<"en">>, #{}), % default 383: ?cfg(language, <<"pl">>, #{<<"general">> => #{<<"language">> => <<"pl">>}}), 384: ?err(#{<<"general">> => #{<<"language">> => <<>>}}). 385: 386: all_metrics_are_global(_Config) -> 387: ?cfg(all_metrics_are_global, false, #{}), % default 388: ?cfg(all_metrics_are_global, true, #{<<"general">> => #{<<"all_metrics_are_global">> => true}}), 389: ?err(#{<<"general">> => #{<<"all_metrics_are_global">> => <<"true">>}}). 390: 391: sm_backend(_Config) -> 392: ?cfg(sm_backend, mnesia, #{}), % default 393: ?cfg(sm_backend, mnesia, #{<<"general">> => #{<<"sm_backend">> => <<"mnesia">>}}), 394: ?cfg(sm_backend, redis, #{<<"general">> => #{<<"sm_backend">> => <<"redis">>}}), 395: ?err(#{<<"general">> => #{<<"sm_backend">> => <<"amnesia">>}}). 396: 397: max_fsm_queue(_Config) -> 398: ?cfg(max_fsm_queue, 100, #{<<"general">> => #{<<"max_fsm_queue">> => 100}}), 399: ?err(#{<<"general">> => #{<<"max_fsm_queue">> => -10}}). 400: 401: http_server_name(_Config) -> 402: ?cfg(cowboy_server_name, "my server", 403: #{<<"general">> => #{<<"http_server_name">> => <<"my server">>}}), 404: ?err(#{<<"general">> => #{<<"http_server_name">> => #{}}}). 405: 406: rdbms_server_type(_Config) -> 407: ?cfg(rdbms_server_type, generic, #{}), % default 408: ?cfg(rdbms_server_type, mssql, #{<<"general">> => #{<<"rdbms_server_type">> => <<"mssql">>}}), 409: ?cfg(rdbms_server_type, pgsql, #{<<"general">> => #{<<"rdbms_server_type">> => <<"pgsql">>}}), 410: ?err(#{<<"general">> => #{<<"rdbms_server_type">> => <<"nosql">>}}). 411: 412: route_subdomains(_Config) -> 413: ?cfgh(route_subdomains, s2s, #{<<"general">> => #{<<"route_subdomains">> => <<"s2s">>}}), 414: ?errh(#{<<"general">> => #{<<"route_subdomains">> => <<"c2s">>}}). 415: 416: mongooseimctl_access_commands(_Config) -> 417: ?cfg(mongooseimctl_access_commands, [], #{}), % default 418: AccessRule = #{<<"commands">> => [<<"join_cluster">>], 419: <<"argument_restrictions">> => #{<<"node">> => <<"mim1@host1">>}}, 420: ?cfg(mongooseimctl_access_commands, [{local, ["join_cluster"], [{node, "mim1@host1"}]}], 421: #{<<"general">> => #{<<"mongooseimctl_access_commands">> => 422: #{<<"local">> => AccessRule}}}), 423: ?cfg(mongooseimctl_access_commands, [{local, all, [{node, "mim1@host1"}]}], 424: #{<<"general">> => #{<<"mongooseimctl_access_commands">> => 425: #{<<"local">> => maps:remove(<<"commands">>, AccessRule)}}}), 426: ?cfg(mongooseimctl_access_commands, [{local, ["join_cluster"], []}], 427: #{<<"general">> => #{<<"mongooseimctl_access_commands">> => 428: #{<<"local">> => maps:remove(<<"argument_restrictions">>, 429: AccessRule)}}}), 430: ?cfg(mongooseimctl_access_commands, [{local, all, []}], 431: #{<<"general">> => #{<<"mongooseimctl_access_commands">> => #{<<"local">> => #{}}}}), 432: ?err(#{<<"general">> => #{<<"mongooseimctl_access_commands">> => 433: #{<<"local">> => #{<<"commands">> => <<"all">>}}}}), 434: ?err(#{<<"general">> => #{<<"mongooseimctl_access_commands">> => 435: #{<<"local">> => #{<<"argument_restrictions">> => 436: [<<"none">>]}}}}). 437: 438: routing_modules(_Config) -> 439: ?cfg(routing_modules, mongoose_router:default_routing_modules(), #{}), % default 440: ?cfg(routing_modules, [mongoose_router_global, mongoose_router_localdomain], 441: #{<<"general">> => #{<<"routing_modules">> => [<<"mongoose_router_global">>, 442: <<"mongoose_router_localdomain">>]}}), 443: ?err(#{<<"general">> => #{<<"routing_modules">> => [<<"moongoose_router_global">>]}}). 444: 445: replaced_wait_timeout(_Config) -> 446: ?cfg({replaced_wait_timeout, ?HOST}, 2000, #{}), % global default 447: ?cfgh(replaced_wait_timeout, 1000, #{<<"general">> => #{<<"replaced_wait_timeout">> => 1000}}), 448: ?errh(#{<<"general">> => #{<<"replaced_wait_timeout">> => 0}}). 449: 450: hide_service_name(_Config) -> 451: ?cfg(hide_service_name, false, #{}), % default 452: ?cfg(hide_service_name, true, #{<<"general">> => #{<<"hide_service_name">> => true}}), 453: ?err(#{<<"general">> => #{<<"hide_service_name">> => []}}). 454: 455: domain_certfile(_Config) -> 456: DomCert = #{<<"domain">> => <<"myxmpp.com">>, 457: <<"certfile">> => <<"priv/cert.pem">>}, 458: ?cfg(domain_certfile, #{<<"myxmpp.com">> => "priv/cert.pem"}, 459: #{<<"general">> => #{<<"domain_certfile">> => [DomCert]}}), 460: ?err([#{reason := invalid_filename}], 461: #{<<"general">> => #{<<"domain_certfile">> => 462: [DomCert#{<<"certfile">> => <<"missing.pem">>}]}}), 463: [?err(#{<<"general">> => #{<<"domain_certfile">> => [maps:without([K], DomCert)]}}) 464: || K <- maps:keys(DomCert)], 465: [?err(#{<<"general">> => #{<<"domain_certfile">> => [DomCert#{K := <<>>}]}}) 466: || K <- maps:keys(DomCert)], 467: ?err(#{<<"general">> => #{<<"domain_certfile">> => [DomCert, DomCert]}}). 468: 469: %% tests: listen 470: 471: listen_duplicate(_Config) -> 472: ?cfg(listen, [listener(c2s, #{port => 5222}), 473: listener(c2s, #{port => 5223})], 474: #{<<"listen">> => #{<<"c2s">> => [#{<<"port">> => 5222, <<"ip_address">> => <<"0">>}, 475: #{<<"port">> => 5223}]}}), 476: ?err([#{reason := duplicate_listeners, 477: duplicates := [{5222, {0, 0, 0, 0}, tcp}]}], 478: #{<<"listen">> => #{<<"c2s">> => [#{<<"port">> => 5222, <<"ip_address">> => <<"0">>}, 479: #{<<"port">> => 5222}]}}), 480: ?err([#{reason := duplicate_listeners, 481: duplicates := [{5222, {0, 0, 0, 0}, tcp}]}], 482: #{<<"listen">> => #{<<"c2s">> => [#{<<"port">> => 5222, <<"ip_address">> => <<"0">>}], 483: <<"s2s">> => [#{<<"port">> => 5222}]}}). 484: 485: listen_c2s(_Config) -> 486: T = fun(Opts) -> listen_raw(c2s, maps:merge(#{<<"port">> => 5222}, Opts)) end, 487: P = [listen, 1], 488: ?cfg(P, config([listen, c2s], #{port => 5222}), T(#{})), 489: test_listen(P, T), 490: test_listen_xmpp(P, T), 491: ?cfg(P ++ [access], rule1, T(#{<<"access">> => <<"rule1">>})), 492: ?cfg(P ++ [shaper], c2s_shaper, T(#{<<"shaper">> => <<"c2s_shaper">>})), 493: ?cfg(P ++ [zlib], 1024, T(#{<<"zlib">> => 1024})), 494: ?cfg(P ++ [max_fsm_queue], 1000, T(#{<<"max_fsm_queue">> => 1000})), 495: ?cfg(P ++ [allowed_auth_methods], [rdbms, http], 496: T(#{<<"allowed_auth_methods">> => [<<"rdbms">>, <<"http">>]})), 497: ?err(T(#{<<"access">> => <<>>})), 498: ?err(T(#{<<"shaper">> => <<>>})), 499: ?err(T(#{<<"zlib">> => 0})), 500: ?err(T(#{<<"max_fsm_queue">> => 0})), 501: ?err(T(#{<<"allowed_auth_methods">> => [<<"bad_method">>]})), 502: ?err(T(#{<<"allowed_auth_methods">> => [<<"rdbms">>, <<"rdbms">>]})). 503: 504: listen_c2s_fast_tls(_Config) -> 505: T = fun(Opts) -> listen_raw(c2s, #{<<"port">> => 5222, 506: <<"tls">> => Opts}) end, 507: P = [listen, 1, tls], 508: ?cfg(P, [], T(#{<<"module">> => <<"fast_tls">>})), 509: ?cfg(P, [starttls], T(#{<<"mode">> => <<"starttls">>})), 510: ?cfg(P, [verify_peer], T(#{<<"verify_peer">> => true})), 511: ?cfg(P, [verify_none], T(#{<<"verify_peer">> => false})), 512: ?cfg(P, [{certfile, "priv/cert.pem"}], T(#{<<"certfile">> => <<"priv/cert.pem">>})), 513: ?cfg(P, [{cafile, "priv/ca.pem"}], T(#{<<"cacertfile">> => <<"priv/ca.pem">>})), 514: ?cfg(P, [{dhfile, "priv/dh.pem"}], T(#{<<"dhfile">> => <<"priv/dh.pem">>})), 515: ?cfg(P, [{ciphers, "TLS_AES_256_GCM_SHA384"}], 516: T(#{<<"ciphers">> => <<"TLS_AES_256_GCM_SHA384">>})), 517: ?cfg(P, [{protocol_options, ["nosslv2"]}], T(#{<<"protocol_options">> => [<<"nosslv2">>]})), 518: ?err(T(#{<<"mode">> => <<"stopttls">>})), 519: ?err(T(#{<<"module">> => <<"slow_tls">>})), 520: ?err(T(#{<<"verify_peer">> => <<"maybe">>})), 521: ?err(T(#{<<"crl_files">> => [<<"file1">>, <<"file2">>]})), % only for just_tls 522: ?err(T(#{<<"certfile">> => <<"no_such_file.pem">>})), 523: ?err(T(#{<<"cacertfile">> => <<"no_such_file.pem">>})), 524: ?err(T(#{<<"dhfile">> => <<"no_such_file.pem">>})), 525: ?err(T(#{<<"ciphers">> => [<<"TLS_AES_256_GCM_SHA384">>]})), 526: ?err(T(#{<<"protocol_options">> => [<<>>]})). 527: 528: listen_c2s_just_tls(_Config) -> 529: T = fun(Opts) -> listen_raw(c2s, #{<<"port">> => 5222, 530: <<"tls">> => Opts#{<<"module">> => <<"just_tls">>}}) end, 531: P = [listen, 1, tls], 532: BaseOpts = [{tls_module, just_tls}], 533: ?cfg(P, BaseOpts, T(#{})), 534: ?cfg(P, BaseOpts ++ [{ssl_options, [{verify_fun, {selfsigned_peer, false}}]}], 535: T(#{<<"verify_mode">> => <<"selfsigned_peer">>, <<"disconnect_on_failure">> => false})), 536: ?cfg(P, BaseOpts ++ [{ssl_options, [{verify_fun, {peer, true}}]}], 537: T(#{<<"verify_mode">> => <<"peer">>})), 538: ?cfg(P, BaseOpts ++ [{crlfiles, ["file1", "file2"]}], 539: T(#{<<"crl_files">> => [<<"file1">>, <<"file2">>]})), 540: ?cfg(P, BaseOpts ++ [{ssl_options, [{certfile, "priv/cert.pem"}]}], 541: T(#{<<"certfile">> => <<"priv/cert.pem">>})), 542: ?cfg(P, BaseOpts ++ [{ssl_options, [{cacertfile, "priv/ca.pem"}]}], 543: T(#{<<"cacertfile">> => <<"priv/ca.pem">>})), 544: ?cfg(P, BaseOpts ++ [{ssl_options, [{dhfile, "priv/dh.pem"}]}], 545: T(#{<<"dhfile">> => <<"priv/dh.pem">>})), 546: ?cfg(P, BaseOpts ++ [{ssl_options, [{ciphers, "TLS_AES_256_GCM_SHA384"}]}], 547: T(#{<<"ciphers">> => <<"TLS_AES_256_GCM_SHA384">>})), 548: ?cfg(P, BaseOpts ++ [{ssl_options, [{versions, ['tlsv1.2', 'tlsv1.3']}]}], 549: T(#{<<"versions">> => [<<"tlsv1.2">>, <<"tlsv1.3">>]})), 550: ?err(T(#{<<"verify_mode">> => <<"whatever">>})), 551: ?err(T(#{<<"verify_mode">> => <<"peer">>, <<"disconnect_on_failure">> => <<"sometimes">>})), 552: ?err(T(#{<<"crl_files">> => [<<>>]})), 553: ?err(T(#{<<"versions">> => <<"tlsv1.2">>})), 554: ?err(T(#{<<"protocol_options">> => [<<"nosslv2">>]})). % only for fast_tls 555: 556: listen_s2s(_Config) -> 557: T = fun(Opts) -> listen_raw(s2s, maps:merge(#{<<"port">> => 5269}, Opts)) end, 558: P = [listen, 1], 559: ?cfg(P, config([listen, s2s], #{port => 5269}), T(#{})), 560: test_listen(P, T), 561: test_listen_xmpp(P, T), 562: ?cfg(P ++ [shaper], s2s_shaper, T(#{<<"shaper">> => <<"s2s_shaper">>})), 563: ?err(T(#{<<"shaper">> => <<>>})). 564: 565: listen_s2s_tls(_Config) -> 566: T = fun(Opts) -> listen_raw(s2s, #{<<"port">> => 5269, <<"tls">> => Opts}) end, 567: P = [listen, 1, tls], 568: ?cfg(P, [{cafile, "priv/ca.pem"}], T(#{<<"cacertfile">> => <<"priv/ca.pem">>})), 569: ?cfg(P, [{dhfile, "priv/dh.pem"}], T(#{<<"dhfile">> => <<"priv/dh.pem">>})), 570: ?cfg(P, [{ciphers, "TLS_AES_256_GCM_SHA384"}], 571: T(#{<<"ciphers">> => <<"TLS_AES_256_GCM_SHA384">>})), 572: ?cfg(P, [{protocol_options, ["nosslv2"]}], T(#{<<"protocol_options">> => [<<"nosslv2">>]})), 573: ?err(T(#{<<"cacertfile">> => <<>>})), 574: ?err(T(#{<<"dhfile">> => 12})), 575: ?err(T(#{<<"ciphers">> => [<<"TLS_AES_256_GCM_SHA384">>]})), 576: ?err(T(#{<<"protocol_options">> => [<<>>]})). 577: 578: listen_service(_Config) -> 579: T = fun(Opts) -> listen_raw(service, maps:merge(#{<<"port">> => 8888, 580: <<"password">> => <<"secret">>}, Opts)) 581: end, 582: P = [listen, 1], 583: ?cfg(P, config([listen, service], #{port => 8888, password => "secret"}), T(#{})), 584: test_listen(P, T), 585: test_listen_xmpp(P, T), 586: ?cfg(P ++ [access], rule1, T(#{<<"access">> => <<"rule1">>})), 587: ?cfg(P ++ [shaper_rule], fast, T(#{<<"shaper_rule">> => <<"fast">>})), 588: ?cfg(P ++ [check_from], false, T(#{<<"check_from">> => false})), 589: ?cfg(P ++ [hidden_components], true, T(#{<<"hidden_components">> => true})), 590: ?cfg(P ++ [conflict_behaviour], kick_old, T(#{<<"conflict_behaviour">> => <<"kick_old">>})), 591: ?cfg(P ++ [max_fsm_queue], 1000, T(#{<<"max_fsm_queue">> => 1000})), 592: ?err(T(#{<<"access">> => <<>>})), 593: ?err(T(#{<<"shaper_rule">> => <<>>})), 594: ?err(T(#{<<"check_from">> => 1})), 595: ?err(T(#{<<"hidden_components">> => <<"yes">>})), 596: ?err(T(#{<<"conflict_behaviour">> => <<"kill_server">>})), 597: ?err(T(#{<<"password">> => <<>>})), 598: ?err(T(#{<<"password">> => undefined})), 599: ?err(T(#{<<"max_fsm_queue">> => 0})). 600: 601: listen_http(_Config) -> 602: T = fun(Opts) -> listen_raw(http, maps:merge(#{<<"port">> => 5280}, Opts)) end, 603: P = [listen, 1], 604: ?cfg(P, config([listen, http], #{port => 5280}), T(#{})), 605: test_listen(P, T). 606: 607: listen_http_tls(_Config) -> 608: T = fun(Opts) -> listen_raw(http, #{<<"port">> => 5280, <<"tls">> => Opts}) end, 609: P = [listen, 1, tls], 610: ?cfg(P, [{verify, verify_peer}], T(#{<<"verify_peer">> => true})), 611: ?cfg(P, [{verify_mode, peer}], T(#{<<"verify_mode">> => <<"peer">>})), 612: ?cfg(P, [{certfile, "priv/cert.pem"}], T(#{<<"certfile">> => <<"priv/cert.pem">>})), 613: ?cfg(P, [{cacertfile, "priv/ca.pem"}], T(#{<<"cacertfile">> => <<"priv/ca.pem">>})), 614: ?cfg(P, [{dhfile, "priv/dh.pem"}], T(#{<<"dhfile">> => <<"priv/dh.pem">>})), 615: ?cfg(P, [{ciphers, "TLS_AES_256_GCM_SHA384"}], 616: T(#{<<"ciphers">> => <<"TLS_AES_256_GCM_SHA384">>})), 617: ?err(T(#{<<"verify_peer">> => 0})), 618: ?err(T(#{<<"verify_mode">> => <<"pear">>})), 619: ?err(T(#{<<"certfile">> => <<>>})), 620: ?err(T(#{<<"cacertfile">> => <<>>})), 621: ?err(T(#{<<"dhfile">> => 12})), 622: ?err(T(#{<<"ciphers">> => [<<"TLS_AES_256_GCM_SHA384">>]})). 623: 624: listen_http_transport(_Config) -> 625: T = fun(Opts) -> listen_raw(http, #{<<"port">> => 5280, <<"transport">> => Opts}) end, 626: P = [listen, 1, transport], 627: ?cfg(P ++ [num_acceptors], 10, T(#{<<"num_acceptors">> => 10})), 628: ?cfg(P ++ [max_connections], 1024, T(#{<<"max_connections">> => 1024})), 629: ?err(T(#{<<"num_acceptors">> => 0})), 630: ?err(T(#{<<"max_connections">> => -1})). 631: 632: listen_http_protocol(_Config) -> 633: T = fun(Opts) -> listen_raw(http, #{<<"port">> => 5280, <<"protocol">> => Opts}) end, 634: P = [listen, 1, protocol], 635: ?cfg(P ++ [compress], true, T(#{<<"compress">> => true})), 636: ?err(T(#{<<"compress">> => 1})). 637: 638: listen_http_handlers_invalid(_Config) -> 639: T = fun(Opts) -> listen_raw(http, #{<<"port">> => 5280, <<"handlers">> => Opts}) end, 640: ?err(T(#{<<"mod_bosch">> => [#{<<"host">> => <<"dishwasher">>, 641: <<"path">> => <<"/cutlery">>}]})). 642: 643: listen_http_handlers_bosh(_Config) -> 644: test_listen_http_handler(mod_bosh). 645: 646: listen_http_handlers_websockets(_Config) -> 647: {P, T} = test_listen_http_handler(mod_websockets), 648: ?cfg(P ++ [timeout], 30000, T(#{<<"timeout">> => 30000})), 649: ?cfg(P ++ [ping_rate], 20, T(#{<<"ping_rate">> => 20})), 650: ?cfg(P ++ [max_stanza_size], 10000, T(#{<<"max_stanza_size">> => 10000})), 651: ?cfg(P ++ [service], maps:merge(extra_service_listener_config(), #{password => "secret"}), 652: T(#{<<"service">> => #{<<"password">> => <<"secret">>}})), 653: ?err(T(#{<<"timeout">> => -1})), 654: ?err(T(#{<<"ping_rate">> => 0})), 655: ?err(T(#{<<"max_stanza_size">> => 0})), 656: ?err(T(#{<<"service">> => #{}})). 657: 658: listen_http_handlers_client_api(_Config) -> 659: {P, T} = test_listen_http_handler(mongoose_client_api), 660: ?cfg(P ++ [handlers], [mongoose_client_api_messages], 661: T(#{<<"handlers">> => [<<"mongoose_client_api_messages">>]})), 662: ?cfg(P ++ [docs], false, T(#{<<"docs">> => false})), 663: ?err(T(#{<<"handlers">> => [not_a_module]})), 664: ?err(T(#{<<"docs">> => <<"maybe">>})). 665: 666: listen_http_handlers_api(_Config) -> 667: {P, T} = test_listen_http_handler(mongoose_api), 668: ?cfg(P ++ [handlers], [mongoose_api_metrics], 669: T(#{<<"handlers">> => [<<"mongoose_api_metrics">>]})), 670: ?err(T(#{<<"handlers">> => [not_a_module]})). 671: 672: listen_http_handlers_api_admin(_Config) -> 673: {P, T} = test_listen_http_handler(mongoose_api_admin), 674: test_listen_http_handler_creds(P, T). 675: 676: listen_http_handlers_api_client(_Config) -> 677: test_listen_http_handler(mongoose_api_client). 678: 679: listen_http_handlers_domain(_Config) -> 680: {P, T} = test_listen_http_handler(mongoose_domain_handler), 681: test_listen_http_handler_creds(P, T). 682: 683: test_listen_http_handler_creds(P, T) -> 684: CredsRaw = #{<<"username">> => <<"user">>, <<"password">> => <<"pass">>}, 685: ?cfg(P ++ [username], <<"user">>, T(CredsRaw)), 686: ?cfg(P ++ [password], <<"pass">>, T(CredsRaw)), 687: %% Both username and password required. Or none. 688: [?err(T(maps:remove(Key, CredsRaw))) || Key <- maps:keys(CredsRaw)], 689: ?err(CredsRaw#{<<"username">> => 1}), 690: ?err(CredsRaw#{<<"password">> => 1}). 691: 692: test_listen_http_handler(Module) -> 693: T = fun(Opts) -> http_handler_raw(Module, Opts) end, 694: P = [listen, 1, handlers, 1], 695: ?cfg(P, config([listen, http, handlers, Module], #{host => "localhost", path => "/api"}), 696: T(#{})), 697: ?cfg(P ++ [host], '_', T(#{<<"host">> => <<"_">>})), 698: ?cfg(P ++ [path], "/my-path", T(#{<<"path">> => <<"/my-path">>})), 699: ?err(T(#{<<"host">> => <<>>})), 700: ?err(T(#{<<"host">> => undefined})), 701: ?err(T(#{<<"path">> => 12})), 702: ?err(T(#{<<"path">> => undefined})), 703: {P, T}. 704: 705: test_listen(P, T) -> 706: ?cfg(P ++ [ip_address], "192.168.1.16", T(#{<<"ip_address">> => <<"192.168.1.16">>})), 707: ?cfg(P ++ [ip_tuple], {192, 168, 1, 16}, T(#{<<"ip_address">> => <<"192.168.1.16">>})), 708: ?cfg(P ++ [ip_version], 4, T(#{<<"ip_address">> => <<"192.168.1.16">>})), 709: ?cfg(P ++ [ip_address], "2001:db8:3:4:5:6:7:8", 710: T(#{<<"ip_address">> => <<"2001:db8:3:4:5:6:7:8">>})), 711: ?cfg(P ++ [ip_tuple], {8193, 3512, 3, 4, 5, 6, 7, 8}, 712: T(#{<<"ip_address">> => <<"2001:db8:3:4:5:6:7:8">>})), 713: ?cfg(P ++ [ip_version], 6, 714: T(#{<<"ip_address">> => <<"2001:db8:3:4:5:6:7:8">>})), 715: ?cfg(P ++ [ip_version], 4, T(#{<<"ip_version">> => 4})), 716: ?cfg(P ++ [ip_version], 6, T(#{<<"ip_version">> => 6})), 717: ?cfg(P ++ [ip_address], "::", T(#{<<"ip_version">> => 6})), 718: ?cfg(P ++ [ip_tuple], {0, 0, 0, 0, 0, 0, 0, 0}, T(#{<<"ip_version">> => 6})), 719: ?cfg(P ++ [proto], tcp, T(#{<<"proto">> => <<"tcp">>})), 720: ?err(T(#{<<"ip_address">> => <<"192.168.1.999">>})), 721: ?err(T(#{<<"port">> => <<"5222">>})), 722: ?err(T(#{<<"port">> => 522222})), 723: ?err(T(#{<<"port">> => undefined})), 724: ?err(T(#{<<"ip_version">> => 7})), 725: ?err(T(#{<<"proto">> => <<"udp">>})). % only TCP is accepted 726: 727: test_listen_xmpp(P, T) -> 728: ?cfg(P ++ [backlog], 10, T(#{<<"backlog">> => 10})), 729: ?cfg(P ++ [proxy_protocol], true, T(#{<<"proxy_protocol">> => true})), 730: ?cfg(P ++ [hibernate_after], 10, T(#{<<"hibernate_after">> => 10})), 731: ?cfg(P ++ [max_stanza_size], 10000, T(#{<<"max_stanza_size">> => 10000})), 732: ?cfg(P ++ [num_acceptors], 100, T(#{<<"num_acceptors">> => 100})), 733: ?err(T(#{<<"backlog">> => -10})), 734: ?err(T(#{<<"proxy_protocol">> => <<"awesome">>})), 735: ?err(T(#{<<"hibernate_after">> => -10})), 736: ?err(T(#{<<"max_stanza_size">> => <<"unlimited">>})), 737: ?err(T(#{<<"num_acceptors">> => 0})). 738: 739: %% tests: auth 740: 741: auth_methods(_Config) -> 742: ?cfg([{auth, ?HOST}, methods], [], #{}), % global default 743: ?cfgh([auth, methods], [], #{<<"auth">> => #{}}), % default 744: ?cfgh([auth, methods], [internal, rdbms], % default alphabetical order 745: #{<<"auth">> => #{<<"internal">> => #{}, 746: <<"rdbms">> => #{}}}), 747: ?cfgh([auth, methods], [rdbms, internal], % specified order 748: #{<<"auth">> => #{<<"internal">> => #{}, 749: <<"rdbms">> => #{}, 750: <<"methods">> => [<<"rdbms">>, <<"internal">>]}}), 751: ?cfgh([auth, methods], [internal], % only one of the defined methods is enabled 752: #{<<"auth">> => #{<<"internal">> => #{}, 753: <<"rdbms">> => #{}, 754: <<"methods">> => [<<"internal">>]}}), 755: ?errh(#{<<"auth">> => #{<<"rdbms">> => <<"enabled">>}}), 756: ?errh(#{<<"auth">> => #{<<"supernatural">> => #{}}}), 757: ?errh(#{<<"auth">> => #{<<"methods">> => [<<"rdbms">>]}}). 758: 759: auth_password(_Config) -> 760: Defaults = #{format => scram, scram_iterations => 10000}, 761: ?cfg([{auth, ?HOST}, password], Defaults, #{}), % global default 762: ?cfgh([auth, password], Defaults, #{<<"auth">> => #{}}), % default 763: ?cfgh([auth, password], Defaults, #{<<"auth">> => #{<<"password">> => #{}}}), % default 764: ?cfgh([auth, password, format], plain, 765: #{<<"auth">> => #{<<"password">> => #{<<"format">> => <<"plain">>}}}), 766: ?errh(#{<<"auth">> => #{<<"password">> => #{<<"format">> => <<"plane">>}}}), 767: ?cfgh([auth, password, hash], [sha, sha256], 768: #{<<"auth">> => #{<<"password">> => #{<<"hash">> => [<<"sha">>, <<"sha256">>]}}}), 769: ?errh(#{<<"auth">> => #{<<"password">> => #{<<"hash">> => [<<"sha1234">>]}}}), 770: ?errh(#{<<"auth">> => #{<<"password">> => #{<<"harsh">> => [<<"sha">>]}}}), 771: ?cfgh([auth, password, scram_iterations], 1000, 772: #{<<"auth">> => #{<<"password">> => #{<<"scram_iterations">> => 1000}}}), 773: ?errh(#{<<"auth">> => #{<<"password">> => #{<<"scram_iterations">> => false}}}). 774: 775: auth_sasl_external(_Config) -> 776: ?cfg([{auth, ?HOST}, sasl_external], [standard], #{}), % global default 777: ?cfgh([auth, sasl_external], [standard], #{<<"auth">> => #{}}), % default 778: ?cfgh([auth, sasl_external], [standard, 779: common_name, 780: {mod, cyrsasl_external_verification}], 781: #{<<"auth">> => #{<<"sasl_external">> => 782: [<<"standard">>, 783: <<"common_name">>, 784: <<"cyrsasl_external_verification">>]}}), 785: ?errh(#{<<"auth">> => #{<<"sasl_external">> => [<<"unknown">>]}}). 786: 787: auth_sasl_mechanisms(_Config) -> 788: Default = cyrsasl:default_modules(), 789: ?cfg([{auth, ?HOST}, sasl_mechanisms], Default, #{}), % global default 790: ?cfg([{auth, ?HOST}, sasl_mechanisms], Default, #{<<"auth">> => #{}}), % default 791: ?cfgh([auth, sasl_mechanisms], [cyrsasl_external, cyrsasl_scram], 792: #{<<"auth">> => #{<<"sasl_mechanisms">> => [<<"external">>, <<"scram">>]}}), 793: ?errh(#{<<"auth">> => #{<<"sasl_mechanisms">> => [<<"none">>]}}). 794: 795: auth_allow_multiple_connections(_Config) -> 796: ?cfgh([auth, anonymous, allow_multiple_connections], true, 797: auth_raw(<<"anonymous">>, #{<<"allow_multiple_connections">> => true})), 798: ?errh(auth_raw(<<"anonymous">>, #{<<"allow_multiple_connections">> => <<"yes">>})). 799: 800: auth_anonymous_protocol(_Config) -> 801: ?cfgh([auth, anonymous, protocol], login_anon, 802: auth_raw(<<"anonymous">>, #{<<"protocol">> => <<"login_anon">>})), 803: ?errh(auth_raw(<<"anonymous">>, #{<<"protocol">> => <<"none">>})). 804: 805: auth_ldap_pool(_Config) -> 806: ?cfgh([auth, ldap, pool_tag], default, auth_ldap_raw(#{})), % default 807: ?cfgh([auth, ldap, pool_tag], ldap_pool, 808: auth_ldap_raw(#{<<"pool_tag">> => <<"ldap_pool">>})), 809: ?errh(auth_ldap_raw(#{<<"pool_tag">> => <<>>})). 810: 811: auth_ldap_bind_pool(_Config) -> 812: ?cfgh([auth, ldap, bind_pool_tag], bind, auth_ldap_raw(#{})), % default 813: ?cfgh([auth, ldap, bind_pool_tag], ldap_bind_pool, 814: auth_ldap_raw(#{<<"bind_pool_tag">> => <<"ldap_bind_pool">>})), 815: ?errh(auth_ldap_raw(#{<<"bind_pool_tag">> => true})). 816: 817: auth_ldap_base(_Config) -> 818: ?cfgh([auth, ldap, base], <<>>, auth_ldap_raw(#{})), % default 819: ?cfgh([auth, ldap, base], <<"ou=Users,dc=example,dc=com">>, 820: auth_ldap_raw(#{<<"base">> => <<"ou=Users,dc=example,dc=com">>})), 821: ?errh(auth_ldap_raw(#{<<"base">> => 10})). 822: 823: auth_ldap_uids(_Config) -> 824: ?cfgh([auth, ldap, uids], [{<<"uid">>, <<"%u">>}], auth_ldap_raw(#{})), % default 825: ?cfgh([auth, ldap, uids], [{<<"uid1">>, <<"user=%u">>}], 826: auth_ldap_raw(#{<<"uids">> => [#{<<"attr">> => <<"uid1">>, 827: <<"format">> => <<"user=%u">>}]})), 828: ?cfgh([auth, ldap, uids], [<<"uid1">>], 829: auth_ldap_raw(#{<<"uids">> => [#{<<"attr">> => <<"uid1">>}]})), 830: ?errh(auth_ldap_raw(#{<<"uids">> => [#{<<"format">> => <<"user=%u">>}]})). 831: 832: auth_ldap_filter(_Config) -> 833: ?cfgh([auth, ldap, filter], <<>>, auth_ldap_raw(#{})), % default 834: ?cfgh([auth, ldap, filter], <<"(objectClass=inetOrgPerson)">>, 835: auth_ldap_raw(#{<<"filter">> => <<"(objectClass=inetOrgPerson)">>})), 836: ?errh(auth_ldap_raw(#{<<"filter">> => 10})). 837: 838: auth_ldap_dn_filter(_Config) -> 839: ?cfgh([auth, ldap, dn_filter], {undefined, []}, auth_ldap_raw(#{})), % default 840: ?cfgh([auth, ldap, dn_filter], {<<"(user=%u@%d)">>, []}, 841: auth_ldap_raw(#{<<"dn_filter">> => #{<<"filter">> => <<"(user=%u@%d)">>}})), 842: Pattern = <<"(&(name=%s)(owner=%D)(user=%u@%d))">>, 843: ?cfgh([auth, ldap, dn_filter], {Pattern, [<<"sn">>]}, 844: auth_ldap_raw(#{<<"dn_filter">> => #{<<"filter">> => Pattern, 845: <<"attributes">> => [<<"sn">>]}})), 846: ?errh(auth_ldap_raw(#{<<"dn_filter">> => #{<<"attributes">> => [<<"sn">>]}})), 847: ?errh(auth_ldap_raw(#{<<"dn_filter">> => #{<<"filter">> => 12}})), 848: ?errh(auth_ldap_raw(#{<<"dn_filter">> => #{<<"filter">> => Pattern, 849: <<"attributes">> => <<"sn">>}})). 850: 851: auth_ldap_local_filter(_Config) -> 852: ?cfgh([auth, ldap, local_filter], undefined, auth_ldap_raw(#{})), % default 853: Filter = #{<<"operation">> => <<"equal">>, 854: <<"attribute">> => <<"accountStatus">>, 855: <<"values">> => [<<"enabled">>]}, 856: ?cfgh([auth, ldap, local_filter], {equal, {"accountStatus", ["enabled"]}}, 857: auth_ldap_raw(#{<<"local_filter">> => Filter})), 858: [?errh(auth_ldap_raw(#{<<"local_filter">> => maps:remove(K, Filter)})) || 859: K <- maps:keys(Filter)], 860: ?errh(auth_ldap_raw(#{<<"local_filter">> => Filter#{<<"operation">> := <<"lt">>}})), 861: ?errh(auth_ldap_raw(#{<<"local_filter">> => Filter#{<<"attribute">> := <<>>}})), 862: ?errh(auth_ldap_raw(#{<<"local_filter">> => Filter#{<<"values">> := []}})). 863: 864: auth_ldap_deref(_Config) -> 865: ?cfgh([auth, ldap, deref], never, auth_ldap_raw(#{})), % default 866: ?cfgh([auth, ldap, deref], always, auth_ldap_raw(#{<<"deref">> => <<"always">>})), 867: ?errh(auth_ldap_raw(#{<<"deref">> => <<"sometimes">>})). 868: 869: auth_external(_Config) -> 870: RequiredOpts = #{<<"program">> => <<"/usr/bin/auth">>}, 871: Config = #{program => "/usr/bin/auth", 872: instances => 1}, % default 873: ?cfgh([auth, external], Config, 874: auth_raw(<<"external">>, RequiredOpts)), 875: ?cfgh([auth, external, instances], 2, 876: auth_raw(<<"external">>, RequiredOpts#{<<"instances">> => 2})), 877: ?errh(auth_raw(<<"external">>, #{<<"program">> => <<>>})), 878: ?errh(auth_raw(<<"external">>, #{<<"instances">> => 2})), 879: ?errh(auth_raw(<<"external">>, RequiredOpts#{<<"instances">> => 0})). 880: 881: auth_http_basic_auth(_Config) -> 882: ?cfgh([auth, http, basic_auth], "admin:admin123", 883: auth_raw(<<"http">>, #{<<"basic_auth">> => <<"admin:admin123">>})), 884: ?errh(auth_raw(<<"http">>, #{<<"basic_auth">> => true})). 885: 886: auth_jwt(_Config) -> 887: Opts = #{<<"secret">> => #{<<"value">> => <<"secret123">>}, 888: <<"algorithm">> => <<"HS512">>, 889: <<"username_key">> => <<"user">>}, % tested together as all options are required 890: Config = #{algorithm => <<"HS512">>, 891: secret => {value, "secret123"}, 892: username_key => user}, 893: ?cfgh([auth, jwt], Config, 894: auth_raw(<<"jwt">>, Opts)), 895: ?cfgh([auth, jwt, secret], {file, "/home/user/jwt_secret"}, 896: auth_raw(<<"jwt">>, Opts#{<<"secret">> := #{<<"file">> => <<"/home/user/jwt_secret">>}})), 897: ?cfgh([auth, jwt, secret], {env, "SECRET"}, 898: auth_raw(<<"jwt">>, Opts#{<<"secret">> := #{<<"env">> => <<"SECRET">>}})), 899: ?errh(auth_raw(<<"jwt">>, Opts#{<<"secret">> := #{<<"value">> => 123}})), 900: ?errh(auth_raw(<<"jwt">>, Opts#{<<"secret">> := #{<<"file">> => <<>>}})), 901: ?errh(auth_raw(<<"jwt">>, Opts#{<<"secret">> := #{<<"env">> => <<>>}})), 902: ?errh(auth_raw(<<"jwt">>, Opts#{<<"secret">> := #{<<"file">> => <<"/jwt_secret">>, 903: <<"env">> => <<"SECRET">>}})), 904: ?errh(auth_raw(<<"jwt">>, Opts#{<<"algorithm">> := <<"bruteforce">>})), 905: ?errh(auth_raw(<<"jwt">>, Opts#{<<"username_key">> := <<>>})), 906: [?errh(auth_raw(<<"jwt">>, maps:without([K], Opts))) || K <- maps:keys(Opts)]. 907: 908: auth_riak_bucket_type(_Config) -> 909: ?cfgh([auth, riak, bucket_type], <<"users">>, auth_raw(<<"riak">>, #{})), % default 910: ?cfgh([auth, riak, bucket_type], <<"buckethead">>, 911: auth_raw(<<"riak">>, #{<<"bucket_type">> => <<"buckethead">>})), 912: ?errh(auth_raw(<<"riak">>, #{<<"bucket_type">> => <<>>})). 913: 914: auth_rdbms_users_number_estimate(_Config) -> 915: ?cfgh([auth, rdbms, users_number_estimate], false, auth_raw(<<"rdbms">>, #{})), % default 916: ?cfgh([auth, rdbms, users_number_estimate], true, 917: auth_raw(<<"rdbms">>, #{<<"users_number_estimate">> => true})), 918: ?errh(auth_raw(<<"rdbms">>, #{<<"users_number_estimate">> => 1200})). 919: 920: auth_dummy(_Config) -> 921: ?cfgh([auth, dummy], #{base_time => 50, variance => 450}, auth_raw(<<"dummy">>, #{})), % default 922: ?cfgh([auth, dummy, base_time], 0, auth_raw(<<"dummy">>, #{<<"base_time">> => 0})), 923: ?cfgh([auth, dummy, variance], 10, auth_raw(<<"dummy">>, #{<<"variance">> => 10})), 924: ?errh(auth_raw(<<"dummy">>, #{<<"base_time">> => -5})), 925: ?errh(auth_raw(<<"dummy">>, #{<<"variance">> => 0})). 926: 927: %% tests: outgoing_pools 928: 929: pool_type(_Config) -> 930: ?cfg(pool_config(#{type => http}), 931: pool_raw(<<"http">>, <<"default">>, #{})), 932: ?err(pool_raw(<<"swimming_pool">>, <<"default">>, #{})). 933: 934: pool_tag(_Config) -> 935: ?cfg(pool_config(#{type => http, tag => my_pool}), 936: pool_raw(<<"http">>, <<"my_pool">>, #{})), 937: ?err(pool_raw(<<"http">>, 1000, #{})). 938: 939: pool_scope(_Config) -> 940: ?cfg(pool_config(#{type => http, scope => host}), 941: pool_raw(<<"http">>, <<"default">>, #{<<"scope">> => <<"host">>})), 942: ?cfg(pool_config(#{type => http, scope => <<"localhost">>}), 943: pool_raw(<<"http">>, <<"default">>, #{<<"scope">> => <<"single_host">>, 944: <<"host">> => <<"localhost">>})), 945: ?err(pool_raw(<<"http">>, <<"default">>, #{<<"scope">> => <<"whatever">>})), 946: ?err(pool_raw(<<"http">>, <<"default">>, #{<<"scope">> => <<"single_host">>})). 947: 948: pool_workers(_Config) -> 949: ?cfg(pool_config(#{type => http, opts => #{workers => 11}}), 950: pool_raw(<<"http">>, <<"default">>, #{<<"workers">> => 11})), 951: ?err(pool_raw(<<"http">>, <<"default">>, #{<<"workers">> => 0})). 952: 953: pool_strategy(_Config) -> 954: ?cfg(pool_config(#{type => http, opts => #{strategy => random_worker}}), 955: pool_raw(<<"http">>, <<"default">>, #{<<"strategy">> => <<"random_worker">>})), 956: ?err(pool_raw(<<"http">>, <<"default">>, #{<<"strategy">> => <<"worst_worker">>})). 957: 958: pool_call_timeout(_Config) -> 959: ?cfg(pool_config(#{type => http, opts => #{call_timeout => 999}}), 960: pool_raw(<<"http">>, <<"default">>, #{<<"call_timeout">> => 999})), 961: ?err(pool_raw(<<"http">>, <<"default">>, #{<<"call_timeout">> => 0})). 962: 963: pool_rdbms_settings(_Config) -> 964: ?cfg(pool_config(#{type => rdbms, conn_opts => #{server => "DSN=mydb"}}), 965: pool_conn_raw(<<"rdbms">>, #{<<"driver">> => <<"odbc">>, 966: <<"settings">> => <<"DSN=mydb">>})), 967: ?err(pool_conn_raw(<<"rdbms">>, #{<<"driver">> => <<"mysql">>, 968: <<"settings">> => <<"DSN=mydb">>})), 969: ?err(pool_conn_raw(<<"rdbms">>, #{<<"driver">> => <<"odbc">>, 970: <<"settings">> => true})), 971: ?err(pool_conn_raw(<<"rdbms">>, #{<<"driver">> => <<"odbc">>})). 972: 973: pool_rdbms_keepalive_interval(_Config) -> 974: ?cfg(pool_config(#{type => rdbms, conn_opts => #{server => "DSN=mydb", 975: keepalive_interval => 1000}}), 976: pool_conn_raw(<<"rdbms">>, #{<<"driver">> => <<"odbc">>, 977: <<"settings">> => <<"DSN=mydb">>, 978: <<"keepalive_interval">> => 1000})), 979: ?err(pool_conn_raw(<<"rdbms">>, #{<<"driver">> => <<"odbc">>, 980: <<"settings">> => <<"DSN=mydb">>, 981: <<"keepalive_interval">> => false})). 982: 983: pool_rdbms_server(_Config) -> 984: ServerOpts = rdbms_opts(), 985: ?cfg(pool_config(#{type => rdbms, 986: conn_opts => #{server => {pgsql, "localhost", "db", "dbuser", "secret"}}}), 987: pool_conn_raw(<<"rdbms">>, ServerOpts)), 988: ?err(pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"driver">> := <<"odbc">>})), 989: [?err(pool_conn_raw(<<"rdbms">>, maps:without([K], ServerOpts))) || 990: K <- maps:keys(ServerOpts)], 991: [?err(pool_conn_raw(<<"rdbms">>, ServerOpts#{K := 123})) || 992: K <- maps:keys(ServerOpts)]. 993: 994: pool_rdbms_port(_Config) -> 995: ServerOpts = rdbms_opts(), 996: ?cfg(pool_config(#{type => rdbms, 997: conn_opts => #{server => {pgsql, "localhost", 1234, "db", "dbuser", "secret"}}}), 998: pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"port">> => 1234})), 999: ?err(pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"port">> => <<"airport">>})). 1000: 1001: pool_rdbms_tls(_Config) -> 1002: ServerOpts = rdbms_opts(), 1003: ?cfg(pool_config(#{type => rdbms, 1004: conn_opts => #{server => {pgsql, "localhost", "db", "dbuser", "secret", 1005: [{ssl, required}]}}}), 1006: pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"tls">> => #{<<"required">> => true}})), 1007: ?cfg(pool_config(#{type => rdbms, 1008: conn_opts => #{server => {pgsql, "localhost", "db", "dbuser", "secret", 1009: [{ssl, true}]}}}), 1010: pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"tls">> => #{}})), 1011: ?cfg(pool_config(#{type => rdbms, 1012: conn_opts => #{server => {mysql, "localhost", "db", "dbuser", "secret", []}}}), 1013: pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"driver">> => <<"mysql">>, 1014: <<"tls">> => #{}})), 1015: ?cfg(pool_config(#{type => rdbms, 1016: conn_opts => #{server => {pgsql, "localhost", 1234, "db", "dbuser", "secret", 1017: [{ssl, true}]}}}), 1018: pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"tls">> => #{}, 1019: <<"port">> => 1234})), 1020: 1021: %% one option tested here as they are all checked by 'listen_tls_*' tests 1022: ?cfg(pool_config(#{type => rdbms, 1023: conn_opts => #{server => {pgsql, "localhost", "db", "dbuser", "secret", 1024: [{ssl, true}, {ssl_opts, [{certfile, "cert.pem"}]}]}}}), 1025: pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"tls">> => 1026: #{<<"certfile">> => <<"cert.pem">>}})), 1027: ?err(pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"tls">> => 1028: #{<<"certfile">> => true}})), 1029: ?err(pool_conn_raw(<<"rdbms">>, ServerOpts#{<<"tls">> => <<"secure">>})). 1030: 1031: pool_http_host(_Config) -> 1032: ?cfg(pool_config(#{type => http, conn_opts => #{server => "https://localhost:8443"}}), 1033: pool_conn_raw(<<"http">>, #{<<"host">> => <<"https://localhost:8443">>})), 1034: ?err(pool_conn_raw(<<"http">>, #{<<"host">> => 8443})), 1035: ?err(pool_conn_raw(<<"http">>, #{<<"host">> => ""})). 1036: 1037: pool_http_path_prefix(_Config) -> 1038: ?cfg(pool_config(#{type => http, conn_opts => #{path_prefix => "/my_path/"}}), 1039: pool_conn_raw(<<"http">>, #{<<"path_prefix">> => <<"/my_path/">>})), 1040: ?err(pool_conn_raw(<<"http">>, #{<<"path_prefix">> => 8443})), 1041: ?err(pool_conn_raw(<<"http">>, #{<<"path_prefix">> => ""})). 1042: 1043: pool_http_request_timeout(_Config) -> 1044: ?cfg(pool_config(#{type => http, conn_opts => #{request_timeout => 999}}), 1045: pool_conn_raw(<<"http">>, #{<<"request_timeout">> => 999})), 1046: ?err(pool_conn_raw(<<"http">>, #{<<"request_timeout">> => -1000})), 1047: ?err(pool_conn_raw(<<"http">>, #{<<"request_timeout">> => <<"infinity">>})). 1048: 1049: pool_http_tls(_Config) -> 1050: ?cfg(pool_config(#{type => http, conn_opts => #{http_opts => [{certfile, "cert.pem"}]}}), 1051: pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"certfile">> => <<"cert.pem">>}})), 1052: ?cfg(pool_config(#{type => http, 1053: conn_opts => #{http_opts => [{certfile, "cert.pem"}, 1054: {verify, verify_peer}, 1055: {cacertfile, "priv/ca.pem"}, 1056: {server_name_indication, disable}]}}), 1057: pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"certfile">> => <<"cert.pem">>, 1058: <<"verify_peer">> => true, 1059: <<"cacertfile">> => <<"priv/ca.pem">>, 1060: <<"server_name_indication">> => false}})), 1061: ?cfg(pool_config(#{type => http, 1062: conn_opts => #{http_opts => [{certfile, "cert.pem"}, 1063: {verify, verify_peer}, 1064: {cacertfile, "priv/ca.pem"}, 1065: {server_name_indication, "domain.com"}]}}), 1066: pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"certfile">> => <<"cert.pem">>, 1067: <<"verify_peer">> => true, 1068: <<"cacertfile">> => <<"priv/ca.pem">>, 1069: <<"server_name_indication">> => true, 1070: <<"server_name_indication_host">> => <<"domain.com">>}})), 1071: ?cfg(pool_config(#{type => http, 1072: conn_opts => #{http_opts => [{certfile, "cert.pem"}, 1073: {verify, verify_peer}, 1074: {cacertfile, "priv/ca.pem"}, 1075: {server_name_indication, "domain.com"}, 1076: {customize_hostname_check, 1077: [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]}]}}), 1078: pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"certfile">> => <<"cert.pem">>, 1079: <<"verify_peer">> => true, 1080: <<"cacertfile">> => <<"priv/ca.pem">>, 1081: <<"server_name_indication">> => true, 1082: <<"server_name_indication_host">> => <<"domain.com">>, 1083: <<"server_name_indication_protocol">> => <<"https">>}})), 1084: ?cfg(pool_config(#{type => http, 1085: conn_opts => #{http_opts => [{verify, verify_peer}, 1086: {cacertfile, "priv/ca.pem"}]}}), 1087: pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"verify_peer">> => true, 1088: <<"cacertfile">> => <<"priv/ca.pem">>}})), 1089: ?err(pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"verify_peer">> => true, 1090: <<"cacertfile">> => <<"priv/ca.pem">>, 1091: <<"server_name_indication">> => <<"domain.com">>, 1092: <<"server_name_indication_host">> => <<"domain.com">>}})), 1093: ?err(pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"verify_peer">> => true, 1094: <<"cacertfile">> => <<"priv/ca.pem">>, 1095: <<"server_name_indication">> => <<"true">>, 1096: <<"server_name_indication_host">> => <<"domain.com">>, 1097: <<"server_name_indication_protocol">> => <<"non_value">>}})), 1098: ?err(pool_conn_raw(<<"http">>, #{<<"tls">> => #{<<"certfile">> => true}})), 1099: ?err(pool_conn_raw(<<"http">>, #{<<"tls">> => <<"secure">>})). 1100: 1101: pool_redis_host(_Config) -> 1102: ?cfg(pool_config(#{type => redis, conn_opts => #{host => "my_host"}}), 1103: pool_conn_raw(<<"redis">>, #{<<"host">> => <<"my_host">>})), 1104: ?err(pool_conn_raw(<<"redis">>, #{<<"host">> => 8443})), 1105: ?err(pool_conn_raw(<<"redis">>, #{<<"host">> => ""})). 1106: 1107: pool_redis_port(_Config) -> 1108: ?cfg(pool_config(#{type => redis, conn_opts => #{port => 9999}}), 1109: pool_conn_raw(<<"redis">>, #{<<"port">> => 9999})), 1110: ?err(pool_conn_raw(<<"redis">>, #{<<"port">> => 666666})), 1111: ?err(pool_conn_raw(<<"redis">>, #{<<"port">> => <<"airport">>})). 1112: 1113: pool_redis_database(_Config) -> 1114: ?cfg(pool_config(#{type => redis, conn_opts => #{database => 1}}), 1115: pool_conn_raw(<<"redis">>, #{<<"database">> => 1})), 1116: ?err(pool_conn_raw(<<"redis">>, #{<<"database">> => -1})), 1117: ?err(pool_conn_raw(<<"redis">>, #{<<"database">> => <<"my_database">>})). 1118: 1119: pool_redis_password(_Config) -> 1120: ?cfg(pool_config(#{type => redis, conn_opts => #{password => "password1"}}), 1121: pool_conn_raw(<<"redis">>, #{<<"password">> => <<"password1">>})), 1122: ?err(pool_conn_raw(<<"redis">>, #{<<"password">> => 0})). 1123: 1124: pool_riak_address(_Config) -> 1125: ?cfg(pool_config(#{type => riak, conn_opts => #{address => "127.0.0.1"}}), 1126: pool_conn_raw(<<"riak">>, #{<<"address">> => <<"127.0.0.1">>})), 1127: ?err(pool_conn_raw(<<"riak">>, #{<<"address">> => 66})), 1128: ?err(pool_conn_raw(<<"riak">>, #{<<"address">> => <<"">>})). 1129: 1130: pool_riak_port(_Config) -> 1131: ?cfg(pool_config(#{type => riak, conn_opts => #{port => 8087}}), 1132: pool_conn_raw(<<"riak">>, #{<<"port">> => 8087})), 1133: ?err(pool_conn_raw(<<"riak">>, #{<<"port">> => 666666})), 1134: ?err(pool_conn_raw(<<"riak">>, #{<<"port">> => <<"airport">>})). 1135: 1136: pool_riak_credentials(_Config) -> 1137: ?cfg(pool_config(#{type => riak, conn_opts => #{credentials => {"user", "pass"}}}), 1138: pool_conn_raw(<<"riak">>, #{<<"credentials">> => 1139: #{<<"user">> => <<"user">>, <<"password">> => <<"pass">>}})), 1140: ?err(pool_conn_raw(<<"riak">>, #{<<"credentials">> => #{<<"user">> => <<"user">>}})), 1141: ?err(pool_conn_raw(<<"riak">>, #{<<"credentials">> => 1142: #{<<"user">> => <<"">>, <<"password">> => 011001}})). 1143: 1144: pool_riak_cacertfile(_Config) -> 1145: ?cfg(pool_config(#{type => riak, conn_opts => #{cacertfile => "cacert.pem"}}), 1146: pool_conn_raw(<<"riak">>, #{<<"tls">> => #{<<"cacertfile">> => <<"cacert.pem">>}})), 1147: ?err(pool_conn_raw(<<"riak">>, #{<<"cacertfile">> => <<"">>})). 1148: 1149: pool_riak_tls(_Config) -> 1150: %% make sure these options are not extracted out of 'ssl_opts' 1151: %% all the TLS options are checked by 'listen_tls_*' tests 1152: ?cfg(pool_config(#{type => riak, 1153: conn_opts => #{ssl_opts => [{certfile, "path/to/cert.pem"}, 1154: {dhfile, "cert.pem"}, 1155: {keyfile, "path/to/key.pem"}]}}), 1156: pool_conn_raw(<<"riak">>, #{<<"tls">> => #{<<"certfile">> => <<"path/to/cert.pem">>, 1157: <<"dhfile">> => <<"cert.pem">>, 1158: <<"keyfile">> => <<"path/to/key.pem">>}})), 1159: ?err(pool_conn_raw(<<"riak">>, #{<<"tls">> => #{<<"dhfile">> => true}})), 1160: ?err(pool_conn_raw(<<"riak">>, #{<<"tls">> => <<"secure">>})). 1161: 1162: pool_cassandra_servers(_Config) -> 1163: ?cfg(pool_config(#{type => cassandra, 1164: conn_opts => #{servers => [{"cassandra_server1.example.com", 9042}, 1165: {"cassandra_server2.example.com", 9042}]}}), 1166: pool_conn_raw(<<"cassandra">>, 1167: #{<<"servers">> => [#{<<"ip_address">> => <<"cassandra_server1.example.com">>, 1168: <<"port">> => 9042}, 1169: #{<<"ip_address">> => <<"cassandra_server2.example.com">>, 1170: <<"port">> => 9042}]})), 1171: ?err(pool_conn_raw(<<"cassandra">>, 1172: #{<<"servers">> => #{<<"ip_address">> => <<"cassandra_server1.example.com">>, 1173: <<"port">> => 9042}})). 1174: 1175: pool_cassandra_keyspace(_Config) -> 1176: ?cfg(pool_config(#{type => cassandra, conn_opts => #{keyspace => big_mongooseim}}), 1177: pool_conn_raw(<<"cassandra">>, #{<<"keyspace">> => <<"big_mongooseim">>})), 1178: ?err(pool_conn_raw(<<"cassandra">>, #{<<"keyspace">> => <<"">>})). 1179: 1180: pool_cassandra_auth(_Config) -> 1181: ?cfg(pool_config(#{type => cassandra, 1182: conn_opts => #{auth => {cqerl_auth_plain_handler, 1183: [{<<"auser">>, <<"secretpass">>}]}}}), 1184: pool_conn_raw(<<"cassandra">>, 1185: #{<<"auth">> => #{<<"plain">> => #{<<"username">> => <<"auser">>, 1186: <<"password">> => <<"secretpass">>}}})), 1187: ?err(pool_conn_raw(<<"cassandra">>, #{<<"tls">> => #{<<"verify">> => <<"verify_none">>}})). 1188: 1189: pool_cassandra_tls(_Config) -> 1190: %% one option tested here as they are all checked by 'listen_tls_*' tests 1191: ?cfg(pool_config(#{type => cassandra, conn_opts => #{ssl => [{verify, verify_none}]}}), 1192: pool_conn_raw(<<"cassandra">>, #{<<"tls">> => #{<<"verify_peer">> => false}})), 1193: ?err(pool_conn_raw(<<"cassandra">>, #{<<"tls">> => #{<<"verify">> => <<"verify_none">>}})). 1194: 1195: pool_elastic_host(_Config) -> 1196: ?cfg(pool_config(#{type => elastic, conn_opts => #{host => "my_host"}}), 1197: pool_conn_raw(<<"elastic">>, #{<<"host">> => <<"my_host">>})), 1198: ?err(pool_conn_raw(<<"elastic">>, #{<<"host">> => <<"">>})). 1199: 1200: pool_elastic_port(_Config) -> 1201: ?cfg(pool_config(#{type => elastic, conn_opts => #{port => 9999}}), 1202: pool_conn_raw(<<"elastic">>, #{<<"port">> => 9999})), 1203: ?err(pool_conn_raw(<<"elastic">>, #{<<"port">> => 122333})), 1204: ?err(pool_conn_raw(<<"elastic">>, #{<<"port">> => <<"airport">>})). 1205: 1206: pool_rabbit_amqp_host(_Config) -> 1207: ?cfg(pool_config(#{type => rabbit, conn_opts => #{amqp_host => "localhost"}}), 1208: pool_conn_raw(<<"rabbit">>, #{<<"amqp_host">> => <<"localhost">>})), 1209: ?err(pool_conn_raw(<<"rabbit">>, #{<<"amqp_host">> => <<"">>})). 1210: 1211: pool_rabbit_amqp_port(_Config) -> 1212: ?cfg(pool_config(#{type => rabbit, conn_opts => #{amqp_port => 5672}}), 1213: pool_conn_raw(<<"rabbit">>, #{<<"amqp_port">> => 5672})), 1214: ?err(pool_conn_raw(<<"rabbit">>, #{<<"amqp_port">> => <<"airport">>})). 1215: 1216: pool_rabbit_amqp_username(_Config) -> 1217: ?cfg(pool_config(#{type => rabbit, conn_opts => #{amqp_username => "guest"}}), 1218: pool_conn_raw(<<"rabbit">>, #{<<"amqp_username">> => <<"guest">>})), 1219: ?err(pool_conn_raw(<<"rabbit">>, #{<<"amqp_username">> => <<"">>})). 1220: 1221: pool_rabbit_amqp_password(_Config) -> 1222: ?cfg(pool_config(#{type => rabbit, conn_opts => #{amqp_password => "guest"}}), 1223: pool_conn_raw(<<"rabbit">>, #{<<"amqp_password">> => <<"guest">>})), 1224: ?err(pool_conn_raw(<<"rabbit">>, #{<<"amqp_password">> => <<"">>})). 1225: 1226: pool_rabbit_amqp_confirms_enabled(_Config) -> 1227: ?cfg(pool_config(#{type => rabbit, conn_opts => #{confirms_enabled => true}}), 1228: pool_conn_raw(<<"rabbit">>, #{<<"confirms_enabled">> => true})), 1229: ?err(pool_conn_raw(<<"rabbit">>, #{<<"confirms_enabled">> => <<"yes">>})). 1230: 1231: pool_rabbit_amqp_max_worker_queue_len(_Config) -> 1232: ?cfg(pool_config(#{type => rabbit, conn_opts => #{max_worker_queue_len => 100}}), 1233: pool_conn_raw(<<"rabbit">>, #{<<"max_worker_queue_len">> => 100})), 1234: ?err(pool_conn_raw(<<"rabbit">>, #{<<"max_worker_queue_len">> => 0})). 1235: 1236: pool_ldap_port(_Config) -> 1237: ?cfg(pool_config(#{type => ldap, conn_opts => #{port => 389}}), 1238: pool_conn_raw(<<"ldap">>, #{<<"port">> => 389})), 1239: ?err(pool_conn_raw(<<"ldap">>, #{<<"port">> => <<"airport">>})). 1240: 1241: pool_ldap_servers(_Config) -> 1242: ?cfg(pool_config(#{type => ldap, 1243: conn_opts => #{servers => ["primary-ldap-server.example.com", 1244: "secondary-ldap-server.example.com"]}}), 1245: pool_conn_raw(<<"ldap">>, #{<<"servers">> => [<<"primary-ldap-server.example.com">>, 1246: <<"secondary-ldap-server.example.com">>]})), 1247: ?err(pool_conn_raw(<<"ldap">>, #{<<"servers">> => #{<<"server">> => <<"example.com">>}})). 1248: 1249: pool_ldap_encrypt(_Config) -> 1250: ?cfg(pool_config(#{type => ldap, conn_opts => #{encrypt => tls}}), 1251: pool_conn_raw(<<"ldap">>, #{<<"encrypt">> => <<"tls">>})), 1252: ?err(pool_conn_raw(<<"ldap">>, #{<<"encrypt">> => true})). 1253: 1254: pool_ldap_rootdn(_Config) -> 1255: ?cfg(pool_config(#{type => ldap, conn_opts => #{rootdn => <<"my_rootdn">>}}), 1256: pool_conn_raw(<<"ldap">>, #{<<"rootdn">> => <<"my_rootdn">>})), 1257: ?err(pool_conn_raw(<<"ldap">>, #{<<"rootdn">> => false})). 1258: 1259: pool_ldap_password(_Config) -> 1260: ?cfg(pool_config(#{type => ldap, conn_opts => #{password => <<"pass">>}}), 1261: pool_conn_raw(<<"ldap">>, #{<<"password">> => <<"pass">>})), 1262: ?err(pool_conn_raw(<<"ldap">>, #{<<"password">> => true})). 1263: 1264: pool_ldap_connect_interval(_Config) -> 1265: ?cfg(pool_config(#{type => ldap, conn_opts => #{connect_interval => 9999}}), 1266: pool_conn_raw(<<"ldap">>, #{<<"connect_interval">> => 9999})), 1267: ?err(pool_conn_raw(<<"ldap">>, #{<<"connect_interval">> => <<"infinity">>})). 1268: 1269: pool_ldap_tls(_Config) -> 1270: %% one option tested here as they are all checked by 'listen_tls_*' tests 1271: ?cfg(pool_config(#{type => ldap, conn_opts => #{tls_options => [{verify, verify_peer}]}}), 1272: pool_conn_raw(<<"ldap">>, #{<<"tls">> => #{<<"verify_peer">> => true}})), 1273: ?err(pool_conn_raw(<<"ldap">>, #{<<"tls">> => #{<<"verify">> => <<"verify_none">>}})). 1274: 1275: %% tests: shaper, acl, access 1276: shaper(_Config) -> 1277: ?cfg([shaper, normal], #{max_rate => 1000}, 1278: #{<<"shaper">> => #{<<"normal">> => #{<<"max_rate">> => 1000}}}), 1279: ?err(#{<<"shaper">> => #{<<"unlimited">> => #{<<"max_rate">> => <<"infinity">>}}}), 1280: ?err(#{<<"shaper">> => #{<<"fast">> => #{}}}). 1281: 1282: acl(_Config) -> 1283: ?cfgh([acl, local], [#{match => all}], 1284: #{<<"acl">> => #{<<"local">> => [#{<<"match">> => <<"all">>}]}}), 1285: ?cfgh([acl, local], [#{match => any_hosted_domain}], 1286: #{<<"acl">> => #{<<"local">> => [#{<<"match">> => <<"any_hosted_domain">>}]}}), 1287: ?cfgh([acl, local], [#{match => current_domain, 1288: user_regexp => <<>>}], 1289: #{<<"acl">> => #{<<"local">> => [#{<<"user_regexp">> => <<>>}]}}), 1290: ?cfgh([acl, alice], [#{match => current_domain, 1291: user_regexp => <<"ali.*">>, 1292: server_regexp => <<".*host">>}], 1293: #{<<"acl">> => #{<<"alice">> => [#{<<"user_regexp">> => <<"aLi.*">>, 1294: <<"server_regexp">> => <<".*HosT">>}]}}), 1295: ?cfgh([acl, alice], [#{match => current_domain, 1296: user => <<"alice">>, 1297: server => <<"localhost">>}], 1298: #{<<"acl">> => #{<<"alice">> => [#{<<"user">> => <<"alice">>, 1299: <<"server">> => <<"localhost">>}]}}), 1300: ?errh(#{<<"acl">> => #{<<"local">> => <<"everybody">>}}), 1301: ?errh(#{<<"acl">> => #{<<"local">> => [#{<<"match">> => <<"lit">>}]}}), 1302: ?errh(#{<<"acl">> => #{<<"alice">> => [#{<<"user_glob">> => <<"a*">>, 1303: <<"server_blog">> => <<"bloghost">>}]}}), 1304: ?errh([#{reason := incorrect_acl_condition_value}], 1305: #{<<"acl">> => #{<<"local">> => [#{<<"user">> => <<"@@@">>}]}}). 1306: 1307: acl_merge_host_and_global(_Config) -> 1308: G = #{<<"acl">> => #{<<"admin">> => [#{<<"user">> => <<"george">>}]}}, 1309: H1 = #{<<"acl">> => #{<<"admin">> => [#{<<"user">> => <<"henry">>}]}}, 1310: H2 = #{<<"acl">> => #{<<"hostile">> => [#{<<"user">> => <<"hacker">>}]}}, 1311: ?cfg([{{acl, global}, #{admin => [#{user => <<"george">>, match => current_domain}]}}, 1312: {{acl, ?HOST}, #{admin => [#{user => <<"george">>, match => current_domain}]}}], 1313: maps:merge(G, host_config(G))), 1314: ?cfg([{{acl, global}, #{admin => [#{user => <<"george">>, match => current_domain}]}}, 1315: {{acl, ?HOST}, #{admin => [#{user => <<"george">>, match => current_domain}, 1316: #{user => <<"henry">>, match => current_domain}]}}], 1317: maps:merge(G, host_config(H1))), 1318: ?cfg([{{acl, global}, #{admin => [#{user => <<"george">>, match => current_domain}]}}, 1319: {{acl, ?HOST}, #{admin => [#{user => <<"george">>, match => current_domain}], 1320: hostile => [#{user => <<"hacker">>, match => current_domain}]}}], 1321: maps:merge(G, host_config(H2))). 1322: 1323: access(_Config) -> 1324: ?cfgh([access, c2s], [#{acl => blocked, value => deny}, 1325: #{acl => all, value => allow}], 1326: access_raw(<<"c2s">>, [#{<<"acl">> => <<"blocked">>, <<"value">> => <<"deny">>}, 1327: #{<<"acl">> => <<"all">>, <<"value">> => <<"allow">>}])), 1328: ?cfgh([access, max_user_sessions], [#{acl => all, value => 10}], 1329: access_raw(<<"max_user_sessions">>, [#{<<"acl">> => <<"all">>, <<"value">> => 10}])), 1330: ?errh(access_raw(<<"max_user_sessions">>, [#{<<"acl">> => <<"all">>}])), 1331: ?errh(access_raw(<<"max_user_sessions">>, [#{<<"value">> => 10}])), 1332: ?errh(access_raw(<<"max_user_sessions">>, [#{<<"acl">> => 10, <<"value">> => 10}])). 1333: 1334: access_merge_host_and_global(_Config) -> 1335: G1 = access_raw(<<"c2s">>, [#{<<"acl">> => <<"good">>, <<"value">> => <<"allow">>}]), 1336: G2 = access_raw(<<"c2s">>, [#{<<"acl">> => <<"gangsters">>, <<"value">> => <<"deny">>}, 1337: #{<<"acl">> => <<"all">>, <<"value">> => <<"allow">>}]), 1338: H1 = access_raw(<<"c2s">>, [#{<<"acl">> => <<"harmless">>, <<"value">> => <<"allow">>}]), 1339: H2 = access_raw(<<"s2s">>, [#{<<"acl">> => <<"harmless">>, <<"value">> => <<"allow">>}]), 1340: H3 = access_raw(<<"c2s">>, [#{<<"acl">> => <<"hackers">>, <<"value">> => <<"deny">>}]), 1341: ?cfg([{{access, global}, #{c2s => [#{acl => good, value => allow}]}}, 1342: {{access, ?HOST}, #{c2s => [#{acl => good, value => allow}]}}], 1343: maps:merge(G1, host_config(G1))), 1344: ?cfg([{{access, global}, #{c2s => [#{acl => good, value => allow}]}}, 1345: {{access, ?HOST}, #{c2s => [#{acl => good, value => allow}, 1346: #{acl => harmless, value => allow}]}}], 1347: maps:merge(G1, host_config(H1))), 1348: ?cfg([{{access, global}, #{c2s => [#{acl => good, value => allow}]}}, 1349: {{access, ?HOST}, #{c2s => [#{acl => good, value => allow}], 1350: s2s => [#{acl => harmless, value => allow}]}}], 1351: maps:merge(G1, host_config(H2))), 1352: ?cfg([{{access, global}, #{c2s => [#{acl => gangsters, value => deny}, 1353: #{acl => all, value => allow}]}}, 1354: {{access, ?HOST}, #{c2s => [#{acl => gangsters, value => deny}, 1355: #{acl => hackers, value => deny}, 1356: #{acl => all, value => allow}]}}], 1357: maps:merge(G2, host_config(H3))). 1358: 1359: %% tests: s2s 1360: 1361: s2s_host_config(_Config) -> 1362: DefaultS2S = default_s2s(), 1363: EmptyHostConfig = host_config(#{<<"s2s">> => #{}}), 1364: ?cfg(host_key(s2s), DefaultS2S, 1365: EmptyHostConfig#{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 5}}}), 1366: StartTLSHostConfig = host_config(#{<<"s2s">> => #{<<"use_starttls">> => <<"required">>}}), 1367: ?cfg(host_key(s2s), DefaultS2S#{use_starttls => required}, 1368: StartTLSHostConfig#{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 5}}}). 1369: 1370: s2s_dns_timeout(_Config) -> 1371: ?cfgh([s2s, dns, timeout], 10, #{}), % default 1372: ?cfgh([s2s, dns, timeout], 5, #{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 5}}}), 1373: ?errh(#{<<"s2s">> => #{<<"dns">> => #{<<"timeout">> => 0}}}). 1374: 1375: s2s_dns_retries(_Config) -> 1376: ?cfgh([s2s, dns, retries], 2, #{}), % default 1377: ?cfgh([s2s, dns, retries], 1, #{<<"s2s">> => #{<<"dns">> => #{<<"retries">> => 1}}}), 1378: ?errh(#{<<"s2s">> => #{<<"dns">> => #{<<"retries">> => 0}}}). 1379: 1380: s2s_outgoing_port(_Config) -> 1381: ?cfgh([s2s, outgoing, port], 5269, #{}), % default 1382: ?cfgh([s2s, outgoing, port], 5270, #{<<"s2s">> => #{<<"outgoing">> => #{<<"port">> => 5270}}}), 1383: ?errh(#{<<"s2s">> => #{<<"outgoing">> => #{<<"port">> => <<"http">>}}}). 1384: 1385: s2s_outgoing_ip_versions(_Config) -> 1386: ?cfgh([s2s, outgoing, ip_versions], [4, 6], #{}), % default 1387: ?cfgh([s2s, outgoing, ip_versions], [6, 4], 1388: #{<<"s2s">> => #{<<"outgoing">> => #{<<"ip_versions">> => [6, 4]}}}), 1389: ?errh(#{<<"s2s">> => #{<<"outgoing">> => #{<<"ip_versions">> => []}}}), 1390: ?errh(#{<<"s2s">> => #{<<"outgoing">> => #{<<"ip_versions">> => [<<"http">>]}}}). 1391: 1392: s2s_outgoing_timeout(_Config) -> 1393: ?cfgh([s2s, outgoing, connection_timeout], 10000, #{}), % default 1394: ?cfgh([s2s, outgoing, connection_timeout], 5000, 1395: #{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => 5000}}}), 1396: ?cfgh([s2s, outgoing, connection_timeout], infinity, 1397: #{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => <<"infinity">>}}}), 1398: ?errh(#{<<"s2s">> => #{<<"outgoing">> => #{<<"connection_timeout">> => 0}}}). 1399: 1400: s2s_use_starttls(_Config) -> 1401: ?cfgh([s2s, use_starttls], false, #{}), % default 1402: ?cfgh([s2s, use_starttls], required, #{<<"s2s">> => #{<<"use_starttls">> => <<"required">>}}), 1403: ?errh(#{<<"s2s">> => #{<<"use_starttls">> => <<"unnecessary">>}}). 1404: 1405: s2s_certfile(_Config) -> 1406: ?cfgh([s2s, certfile], "priv/server.pem", #{<<"s2s">> => #{<<"certfile">> => <<"priv/server.pem">>}}), 1407: ?errh([#{reason := invalid_filename}], #{<<"s2s">> => #{<<"certfile">> => <<"nofile.pem">>}}), 1408: ?errh(#{<<"s2s">> => #{<<"certfile">> => []}}). 1409: 1410: s2s_default_policy(_Config) -> 1411: ?cfgh([s2s, default_policy], allow, #{}), % default 1412: ?cfgh([s2s, default_policy], deny, #{<<"s2s">> => #{<<"default_policy">> => <<"deny">>}}), 1413: ?errh(#{<<"s2s">> => #{<<"default_policy">> => <<"ask">>}}). 1414: 1415: s2s_host_policy(_Config) -> 1416: Policy = #{<<"host">> => <<"host1">>, 1417: <<"policy">> => <<"allow">>}, 1418: ?cfgh([s2s, host_policy], #{<<"host1">> => allow}, 1419: #{<<"s2s">> => #{<<"host_policy">> => [Policy]}}), 1420: ?cfgh([s2s, host_policy], #{<<"host1">> => allow, 1421: <<"host2">> => deny}, 1422: #{<<"s2s">> => #{<<"host_policy">> => [Policy, #{<<"host">> => <<"host2">>, 1423: <<"policy">> => <<"deny">>}]}}), 1424: ?errh(#{<<"s2s">> => #{<<"host_policy">> => [maps:without([<<"host">>], Policy)]}}), 1425: ?errh(#{<<"s2s">> => #{<<"host_policy">> => [maps:without([<<"policy">>], Policy)]}}), 1426: ?errh(#{<<"s2s">> => #{<<"host_policy">> => [Policy#{<<"host">> => <<>>}]}}), 1427: ?errh(#{<<"s2s">> => #{<<"host_policy">> => [Policy#{<<"policy">> => <<"huh">>}]}}), 1428: ?errh(#{<<"s2s">> => #{<<"host_policy">> => [Policy, 1429: Policy#{<<"policy">> => <<"deny">>}]}}). 1430: 1431: s2s_address(_Config) -> 1432: Addr = #{<<"host">> => <<"host1">>, 1433: <<"ip_address">> => <<"192.168.1.2">>, 1434: <<"port">> => 5321}, 1435: ?cfgh([s2s, address], #{<<"host1">> => #{ip_address => "192.168.1.2", port => 5321}}, 1436: #{<<"s2s">> => #{<<"address">> => [Addr]}}), 1437: ?cfgh([s2s, address], #{<<"host1">> => #{ip_address => "192.168.1.2"}}, 1438: #{<<"s2s">> => #{<<"address">> => [maps:without([<<"port">>], Addr)]}}), 1439: ?errh(#{<<"s2s">> => #{<<"address">> => [maps:without([<<"host">>], Addr)]}}), 1440: ?errh(#{<<"s2s">> => #{<<"address">> => [maps:without([<<"ip_address">>], Addr)]}}), 1441: ?errh(#{<<"s2s">> => #{<<"address">> => [Addr#{<<"host">> => <<>>}]}}), 1442: ?errh(#{<<"s2s">> => #{<<"address">> => [Addr#{<<"ip_address">> => <<"host2">>}]}}), 1443: ?errh(#{<<"s2s">> => #{<<"address">> => [Addr#{<<"port">> => <<"seaport">>}]}}), 1444: ?errh(#{<<"s2s">> => #{<<"address">> => [Addr, maps:remove(<<"port">>, Addr)]}}). 1445: 1446: s2s_ciphers(_Config) -> 1447: ?cfgh([s2s, ciphers], ejabberd_tls:default_ciphers(), #{}), % default 1448: ?cfgh([s2s, ciphers], "TLSv1.2", 1449: #{<<"s2s">> => #{<<"ciphers">> => <<"TLSv1.2">>}}), 1450: ?errh(#{<<"s2s">> => #{<<"ciphers">> => [<<"cipher1">>, <<"cipher2">>]}}). 1451: 1452: s2s_shared(_Config) -> 1453: ?cfgh([s2s, shared], <<"secret">>, #{<<"s2s">> => #{<<"shared">> => <<"secret">>}}), 1454: ?errh(#{<<"s2s">> => #{<<"shared">> => 536837}}). 1455: 1456: s2s_max_retry_delay(_Config) -> 1457: ?cfgh([s2s, max_retry_delay], 120, #{<<"s2s">> => #{<<"max_retry_delay">> => 120}}), 1458: ?errh(#{<<"s2s">> => #{<<"max_retry_delay">> => 0}}). 1459: 1460: %% modules 1461: 1462: mod_adhoc(_Config) -> 1463: check_module_defaults(mod_adhoc), 1464: check_iqdisc(mod_adhoc), 1465: P = [modules, mod_adhoc], 1466: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_adhoc">> => #{K => V}}} end, 1467: %% report_commands_node is boolean 1468: ?cfgh(P ++ [report_commands_node], true, T(<<"report_commands_node">>, true)), 1469: ?cfgh(P ++ [report_commands_node], false, T(<<"report_commands_node">>, false)), 1470: %% not boolean 1471: ?errh(T(<<"report_commands_node">>, <<"hello">>)). 1472: 1473: mod_auth_token(_Config) -> 1474: check_module_defaults(mod_auth_token), 1475: check_iqdisc(mod_auth_token), 1476: P = [modules, mod_auth_token], 1477: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_auth_token">> => #{K => V}}} end, 1478: ?cfgh(P ++ [backend], rdbms, T(<<"backend">>, <<"rdbms">>)), 1479: ?cfgh(P ++ [validity_period, access], #{unit => minutes, value => 13}, 1480: T(<<"validity_period">>, 1481: #{<<"access">> => #{<<"value">> => 13, <<"unit">> => <<"minutes">>}})), 1482: ?cfgh(P ++ [validity_period, refresh], #{unit => days, value => 31}, 1483: T(<<"validity_period">>, 1484: #{<<"refresh">> => #{<<"value">> => 31, <<"unit">> => <<"days">>}})), 1485: ?errh(T(<<"backend">>, <<"nosql">>)), 1486: ?errh(T(<<"validity_period">>, 1487: #{<<"access">> => #{<<"value">> => -1, <<"unit">> => <<"minutes">>}})), 1488: ?errh(T(<<"validity_period">>, 1489: #{<<"access">> => #{<<"value">> => 10, <<"unit">> => <<"centuries">>}})), 1490: ?errh(T(<<"validity_period">>, #{<<"access">> => #{<<"value">> => 10}})), 1491: ?errh(T(<<"validity_period">>, #{<<"access">> => #{<<"unit">> => <<"days">>}})). 1492: 1493: mod_blocking(_Config) -> 1494: test_privacy_opts(mod_blocking). 1495: 1496: mod_bosh(_Config) -> 1497: check_module_defaults(mod_bosh), 1498: P = [modules, mod_bosh], 1499: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_bosh">> => #{K => V}}} end, 1500: ?cfgh(P ++ [backend], mnesia, T(<<"backend">>, <<"mnesia">>)), 1501: ?cfgh(P ++ [inactivity], 10, T(<<"inactivity">>, 10)), 1502: ?cfgh(P ++ [inactivity], infinity, T(<<"inactivity">>, <<"infinity">>)), 1503: ?cfgh(P ++ [max_wait], 10, T(<<"max_wait">>, 10)), 1504: ?cfgh(P ++ [max_wait], infinity, T(<<"max_wait">>, <<"infinity">>)), 1505: ?cfgh(P ++ [server_acks], true, T(<<"server_acks">>, true)), 1506: ?cfgh(P ++ [server_acks], false, T(<<"server_acks">>, false)), 1507: ?cfgh(P ++ [max_pause], 10, T(<<"max_pause">>, 10)), 1508: ?errh(T(<<"backend">>, <<"nodejs">>)), 1509: ?errh(T(<<"inactivity">>, 0)), 1510: ?errh(T(<<"inactivity">>, <<"10">>)), 1511: ?errh(T(<<"inactivity">>, <<"inactivity">>)), 1512: ?errh(T(<<"max_wait">>, <<"10">>)), 1513: ?errh(T(<<"max_wait">>, 0)), 1514: ?errh(T(<<"server_acks">>, -1)), 1515: ?errh(T(<<"maxpause">>, 0)). 1516: 1517: mod_caps(_Config) -> 1518: check_module_defaults(mod_caps), 1519: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_caps">> => #{K => V}}} end, 1520: P = [modules, mod_caps], 1521: ?cfgh(P ++ [cache_size], 10, T(<<"cache_size">>, 10)), 1522: ?cfgh(P ++ [cache_life_time], 10, T(<<"cache_life_time">>, 10)), 1523: ?errh(T(<<"cache_size">>, 0)), 1524: ?errh(T(<<"cache_size">>, <<"infinity">>)), 1525: ?errh(T(<<"cache_life_time">>, 0)), 1526: ?errh(T(<<"cache_life_time">>, <<"infinity">>)). 1527: 1528: mod_cache_users(_Config) -> 1529: check_module_defaults(mod_cache_users), 1530: P = [modules, mod_cache_users], 1531: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_cache_users">> => #{K => V}}} end, 1532: ?cfgh(P ++ [time_to_live], 8600, T(<<"time_to_live">>, 8600)), 1533: ?cfgh(P ++ [time_to_live], infinity, T(<<"time_to_live">>, <<"infinity">>)), 1534: ?cfgh(P ++ [number_of_segments], 10, T(<<"number_of_segments">>, 10)), 1535: ?cfgh(P ++ [strategy], fifo, T(<<"strategy">>, <<"fifo">>)), 1536: ?errh(T(<<"time_to_live">>, 0)), 1537: ?errh(T(<<"strategy">>, <<"lifo">>)), 1538: ?errh(T(<<"number_of_segments">>, 0)), 1539: ?errh(T(<<"number_of_segments">>, <<"infinity">>)). 1540: 1541: mod_carboncopy(_Config) -> 1542: check_iqdisc(mod_carboncopy). 1543: 1544: mod_csi(_Config) -> 1545: check_module_defaults(mod_csi), 1546: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_csi">> => #{K => V}}} end, 1547: P = [modules, mod_csi], 1548: ?cfgh(P ++ [buffer_max], 10, T(<<"buffer_max">>, 10)), 1549: ?cfgh(P ++ [buffer_max], infinity, T(<<"buffer_max">>, <<"infinity">>)), 1550: ?errh(T(<<"buffer_max">>, -1)). 1551: 1552: mod_disco(_Config) -> 1553: check_module_defaults(mod_disco), 1554: check_iqdisc(mod_disco), 1555: P = [modules, mod_disco], 1556: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_disco">> => #{K => V}}} end, 1557: ?cfgh(P ++ [users_can_see_hidden_services], true, 1558: T(<<"users_can_see_hidden_services">>, true)), 1559: ?cfgh(P ++ [users_can_see_hidden_services], false, 1560: T(<<"users_can_see_hidden_services">>, false)), 1561: %% extra_domains are binaries 1562: ?cfgh(P ++ [extra_domains], [<<"localhost">>, <<"erlang-solutions.com">>], 1563: T(<<"extra_domains">>, [<<"localhost">>, <<"erlang-solutions.com">>])), 1564: ?cfgh(P ++ [extra_domains], [], 1565: T(<<"extra_domains">>, [])), 1566: Info = #{<<"name">> => <<"abuse-address">>, 1567: <<"urls">> => [<<"admin@example.com">>]}, 1568: SpiritUrls = [<<"spirit1@localhost">>, <<"spirit2@localhost">>], 1569: ?cfgh(P ++ [server_info], 1570: [#{name => <<"abuse-address">>, urls => [<<"admin@example.com">>]}, 1571: #{name => <<"friendly-spirits">>, urls => SpiritUrls, modules => [mod_muc, mod_disco]}], 1572: T(<<"server_info">>, [Info, #{<<"name">> => <<"friendly-spirits">>, 1573: <<"urls">> => SpiritUrls, 1574: <<"modules">> => [<<"mod_muc">>, <<"mod_disco">>]}])), 1575: ?errh(T(<<"users_can_see_hidden_services">>, 1)), 1576: ?errh(T(<<"users_can_see_hidden_services">>, <<"true">>)), 1577: ?errh(T(<<"extra_domains">>, [<<"user@localhost">>])), 1578: ?errh(T(<<"extra_domains">>, [1])), 1579: ?errh(T(<<"extra_domains">>, <<"domains domains domains">>)), 1580: ?errh(T(<<"server_info">>, [Info#{<<"name">> => 1}])), 1581: ?errh(T(<<"server_info">>, [Info#{<<"name">> => <<"">>}])), 1582: ?errh(T(<<"server_info">>, [Info#{<<"modules">> => <<"roll">>}])), 1583: ?errh(T(<<"server_info">>, [Info#{<<"modules">> => [<<"meow_meow_meow">>]}])), 1584: ?errh(T(<<"server_info">>, [Info#{<<"urls">> => [1]}])), 1585: ?errh(T(<<"server_info">>, [Info#{<<"urls">> => [<<"">>]}])), 1586: ?errh(T(<<"server_info">>, [maps:remove(<<"name">>, Info)])), 1587: ?errh(T(<<"server_info">>, [maps:remove(<<"urls">>, Info)])). 1588: 1589: mod_extdisco(_Config) -> 1590: check_module_defaults(mod_extdisco), 1591: check_iqdisc(mod_extdisco), 1592: P = [modules, mod_extdisco, service], 1593: T = fun(Opts) -> #{<<"modules">> => 1594: #{<<"mod_extdisco">> => 1595: #{<<"service">> => [Opts]}}} 1596: end, 1597: RequiredOpts = #{<<"type">> => <<"stun">>, <<"host">> => <<"stun1">>}, 1598: Service = #{type => stun, host => <<"stun1">>}, 1599: ?cfgh(P, [Service], T(RequiredOpts)), 1600: ?cfgh(P, [Service#{port => 3478}], T(RequiredOpts#{<<"port">> => 3478})), 1601: ?cfgh(P, [Service#{transport => <<"udp">>}], T(RequiredOpts#{<<"transport">> => <<"udp">>})), 1602: ?cfgh(P, [Service#{username => <<"user">>}], T(RequiredOpts#{<<"username">> => <<"user">>})), 1603: ?cfgh(P, [Service#{password => <<"pass">>}], T(RequiredOpts#{<<"password">> => <<"pass">>})), 1604: [?errh(T(maps:remove(Key, RequiredOpts))) || Key <- maps:keys(RequiredOpts)], 1605: [?errh(T(RequiredOpts#{Key => 1})) || Key <- maps:keys(RequiredOpts)], 1606: ?errh(T(RequiredOpts#{<<"type">> => <<>>})), 1607: ?errh(T(RequiredOpts#{<<"host">> => <<>>})), 1608: ?errh(T(RequiredOpts#{<<"port">> => -1})), 1609: ?errh(T(RequiredOpts#{<<"transport">> => <<>>})), 1610: ?errh(T(RequiredOpts#{<<"username">> => <<>>})), 1611: ?errh(T(RequiredOpts#{<<"password">> => <<>>})). 1612: 1613: mod_inbox(_Config) -> 1614: check_module_defaults(mod_inbox), 1615: check_iqdisc(mod_inbox), 1616: P = [modules, mod_inbox], 1617: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_inbox">> => Opts}} end, 1618: ChatMarkers = [<<"displayed">>, <<"received">>, <<"acknowledged">>], 1619: ?cfgh(P ++ [backend], rdbms, T(#{<<"backend">> => <<"rdbms">>})), 1620: ?cfgh(P ++ [async_writer], #{pool_size => 8}, T(#{<<"async_writer">> => #{<<"pool_size">> => 8}})), 1621: ?cfgh(P ++ [reset_markers], ChatMarkers, T(#{<<"reset_markers">> => ChatMarkers})), 1622: ?cfgh(P ++ [groupchat], [muc, muclight], T(#{<<"groupchat">> => [<<"muc">>, <<"muclight">>]})), 1623: ?cfgh(P ++ [boxes], 1624: [<<"inbox">>, <<"archive">>, <<"bin">>, <<"favourites">>, <<"spam">>], 1625: T(#{<<"boxes">> => [<<"favourites">>, <<"spam">>]})), 1626: ?cfgh(P ++ [bin_ttl], 30, T(#{<<"bin_ttl">> => 30})), 1627: ?cfgh(P ++ [bin_clean_after], 43200000, T(#{<<"bin_clean_after">> => 12})), 1628: ?cfgh(P ++ [aff_changes], true, T(#{<<"aff_changes">> => true})), 1629: ?cfgh(P ++ [remove_on_kicked], false, T(#{<<"remove_on_kicked">> => false})), 1630: ?errh(T(#{<<"backend">> => <<"nodejs">>})), 1631: ?errh(T(#{<<"pool_size">> => -1})), 1632: ?errh(T(#{<<"reset_markers">> => 1})), 1633: ?errh(T(#{<<"reset_markers">> => [<<"destroyed">>]})), 1634: ?errh(T(#{<<"groupchat">> => [<<"test">>]})), 1635: ?errh(T(#{<<"boxes">> => [<<"archive">>]})), 1636: ?errh(T(#{<<"boxes">> => [<<"duplicate">>, <<"duplicate">>]})), 1637: ?errh(T(#{<<"boxes">> => <<"test">>})), 1638: ?errh(T(#{<<"bin_ttl">> => true})), 1639: ?errh(T(#{<<"bin_clean_after">> => -1})), 1640: ?errh(T(#{<<"aff_changes">> => 1})), 1641: ?errh(T(#{<<"remove_on_kicked">> => 1})). 1642: 1643: mod_global_distrib(_Config) -> 1644: P = [modules, mod_global_distrib], 1645: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_global_distrib">> => Opts}} end, 1646: RequiredOpts = global_distrib_required_opts(), 1647: ExpectedCfg = mod_config(mod_global_distrib, global_distrib_expected_config()), 1648: ?cfgh(P, ExpectedCfg, T(RequiredOpts)), 1649: ?cfgh(P ++ [message_ttl], 42, 1650: T(RequiredOpts#{<<"message_ttl">> => 42})), 1651: ?cfgh(P ++ [hosts_refresh_interval], 100, 1652: T(RequiredOpts#{<<"hosts_refresh_interval">> => 100})), 1653: [?errh(T(maps:remove(Key, RequiredOpts))) || Key <- maps:keys(RequiredOpts)], 1654: ?errh(T(RequiredOpts#{<<"global_host">> => <<>>})), 1655: ?errh(T(RequiredOpts#{<<"local_host">> => <<>>})), 1656: ?errh(T(RequiredOpts#{<<"local_host">> => <<"nohost">>})), % passed to 'endpoints', not resolved 1657: ?errh(T(RequiredOpts#{<<"message_ttl">> => -1})), 1658: ?errh(T(RequiredOpts#{<<"hosts_refresh_interval">> => -1})). 1659: 1660: mod_global_distrib_connections(_Config) -> 1661: RequiredOpts = global_distrib_required_opts(), 1662: P = [modules, mod_global_distrib, connections], 1663: T = fun(Opts) -> #{<<"modules">> => 1664: #{<<"mod_global_distrib">> => 1665: RequiredOpts#{<<"connections">> => Opts}}} 1666: end, 1667: ?cfgh(P, global_distrib_expected_connections(), T(#{})), 1668: ?cfgh(P ++ [connections_per_endpoint], 22, 1669: T(#{<<"connections_per_endpoint">> => 22})), 1670: ?cfgh(P ++ [endpoint_refresh_interval], 120, 1671: T(#{<<"endpoint_refresh_interval">> => 120})), 1672: ?cfgh(P ++ [endpoint_refresh_interval_when_empty], 5, 1673: T(#{<<"endpoint_refresh_interval_when_empty">> => 5})), 1674: ?cfgh(P ++ [disabled_gc_interval], 60, 1675: T(#{<<"disabled_gc_interval">> => 60})), 1676: ?errh(T(#{<<"connections_per_endpoint">> => -1})), 1677: ?errh(T(#{<<"endpoint_refresh_interval">> => 0})), 1678: ?errh(T(#{<<"endpoint_refresh_interval_when_empty">> => 0})), 1679: ?errh(T(#{<<"disabled_gc_interval">> => 0})). 1680: 1681: mod_global_distrib_connections_endpoints(_Config) -> 1682: check_mod_global_distrib_endpoint_opts(<<"endpoints">>), 1683: RequiredModOpts = global_distrib_required_opts(), 1684: P = [modules, mod_global_distrib, connections], 1685: T = fun(Opts) -> #{<<"modules">> => 1686: #{<<"mod_global_distrib">> => 1687: RequiredModOpts#{<<"connections">> => #{<<"endpoints">> => Opts}}}} 1688: end, 1689: 1690: %% 'enpoints' propagate to 'advertised_endpoints' and 'resolved_endpoints' 1691: ?cfgh([{P ++ [endpoints], [{"172.16.0.2", 5555}]}, 1692: {P ++ [advertised_endpoints], [{"172.16.0.2", 5555}]}, 1693: {P ++ [resolved_endpoints], [{{172, 16, 0, 2}, 5555}]}], 1694: T([#{<<"host">> => <<"172.16.0.2">>, <<"port">> => 5555}])), 1695: 1696: ?cfgh([{P ++ [endpoints], [{"localhost", 15555}]}, 1697: {P ++ [advertised_endpoints], [{"localhost", 15555}]}, 1698: {P ++ [resolved_endpoints], [{{0, 0, 0, 0, 0, 0, 0, 1}, 15555}, 1699: {{127, 0, 0, 1}, 15555}] 1700: }], 1701: T([#{<<"host">> => <<"localhost">>, <<"port">> => 15555}])), 1702: ?errh(T([#{<<"host">> => <<"172.16.0.299">>, <<"port">> => 5555}])), 1703: ?errh(T([#{<<"host">> => <<"nohost">>, <<"port">> => 15555}])). 1704: 1705: mod_global_distrib_connections_advertised_endpoints(_Config) -> 1706: check_mod_global_distrib_endpoint_opts(<<"advertised_endpoints">>). 1707: 1708: check_mod_global_distrib_endpoint_opts(OptKey) -> 1709: RequiredModOpts = global_distrib_required_opts(), 1710: P = [modules, mod_global_distrib, connections, binary_to_atom(OptKey)], 1711: T = fun(Opts) -> #{<<"modules">> => 1712: #{<<"mod_global_distrib">> => 1713: RequiredModOpts#{<<"connections">> => #{OptKey => Opts}}}} 1714: end, 1715: RequiredOpts = #{<<"host">> => <<"172.16.0.2">>, <<"port">> => 5678}, 1716: ?cfgh(P, [{"172.16.0.2", 5678}], T([RequiredOpts])), 1717: [?errh(T(maps:remove(Key, RequiredOpts))) || Key <- maps:keys(RequiredOpts)], 1718: ?errh(T([RequiredOpts#{<<"host">> => <<>>}])), 1719: ?errh(T([RequiredOpts#{<<"port">> => -1}])). 1720: 1721: mod_global_distrib_connections_tls(_Config) -> 1722: RequiredModOpts = global_distrib_required_opts(), 1723: P = [modules, mod_global_distrib, connections, tls], 1724: T = fun(Opts) -> #{<<"modules">> => 1725: #{<<"mod_global_distrib">> => 1726: RequiredModOpts#{<<"connections">> => #{<<"tls">> => Opts}}}} 1727: end, 1728: RequiredOpts = #{<<"certfile">> => <<"priv/cert.pem">>, 1729: <<"cacertfile">> => <<"priv/ca.pem">>}, 1730: ExpectedCfg = config(P, #{certfile => "priv/cert.pem", cafile => "priv/ca.pem"}), 1731: ?cfgh(P, ExpectedCfg, T(RequiredOpts)), 1732: ?cfgh(P ++ [ciphers], "TLS_AES_256_GCM_SHA384", 1733: T(RequiredOpts#{<<"ciphers">> => <<"TLS_AES_256_GCM_SHA384">>})), 1734: ?cfgh(P ++ [dhfile], "priv/cert.pem", 1735: T(RequiredOpts#{<<"dhfile">> => <<"priv/cert.pem">>})), 1736: [?errh(T(maps:remove(Key, RequiredOpts))) || Key <- maps:keys(RequiredOpts)], 1737: ?errh(T(RequiredOpts#{<<"certfile">> => <<"/this/does/not/exist">>})), 1738: ?errh(T(RequiredOpts#{<<"cacertfile">> => <<"/this/does/not/exist">>})), 1739: ?errh(T(RequiredOpts#{<<"dhfile">> => <<"/this/does/not/exist">>})), 1740: ?errh(T(RequiredOpts#{<<"ciphers">> => 42})). 1741: 1742: mod_global_distrib_redis(_Config) -> 1743: RequiredModOpts = global_distrib_required_opts(), 1744: P = [modules, mod_global_distrib, redis], 1745: T = fun(Opts) -> #{<<"modules">> => 1746: #{<<"mod_global_distrib">> => 1747: RequiredModOpts#{<<"redis">> => Opts}}} 1748: end, 1749: ?cfgh(P, default_config(P), T(#{})), 1750: ?cfgh(P ++ [pool], global_distrib, T(#{<<"pool">> => <<"global_distrib">>})), 1751: ?cfgh(P ++ [expire_after], 120, T(#{<<"expire_after">> => 120})), 1752: ?cfgh(P ++ [refresh_after], 60, T(#{<<"refresh_after">> => 60})), 1753: ?errh(T(#{<<"pool">> => <<"">>})), 1754: ?errh(T(#{<<"expire_after">> => 0})), 1755: ?errh(T(#{<<"refresh_after">> => -1})). 1756: 1757: mod_global_distrib_cache(_Config) -> 1758: RequiredModOpts = global_distrib_required_opts(), 1759: P = [modules, mod_global_distrib, cache], 1760: T = fun(Opts) -> #{<<"modules">> => 1761: #{<<"mod_global_distrib">> => 1762: RequiredModOpts#{<<"cache">> => Opts}}} 1763: end, 1764: ?cfgh(P, default_config(P), T(#{})), 1765: ?cfgh(P ++ [cache_missed], false, T(#{<<"cache_missed">> => false})), 1766: ?cfgh(P ++ [domain_lifetime_seconds], 60, T(#{<<"domain_lifetime_seconds">> => 60})), 1767: ?cfgh(P ++ [jid_lifetime_seconds], 30, T(#{<<"jid_lifetime_seconds">> => 30})), 1768: ?cfgh(P ++ [max_jids], 9999, T(#{<<"max_jids">> => 9999})), 1769: ?errh(T(#{<<"cache_missed">> => <<"yes">>})), 1770: ?errh(T(#{<<"domain_lifetime_seconds">> => -1})), 1771: ?errh(T(#{<<"jid_lifetime_seconds">> => -1})), 1772: ?errh(T(#{<<"max_jids">> => -1})). 1773: 1774: mod_global_distrib_bounce(_Config) -> 1775: RequiredModOpts = global_distrib_required_opts(), 1776: P = [modules, mod_global_distrib, bounce], 1777: T = fun(Opts) -> #{<<"modules">> => 1778: #{<<"mod_global_distrib">> => 1779: RequiredModOpts#{<<"bounce">> => Opts}}} 1780: end, 1781: ?cfgh(P, default_config(P), T(#{})), 1782: ?cfgh(P ++ [enabled], false, T(#{<<"enabled">> => false})), 1783: ?cfgh(P ++ [resend_after_ms], 300, T(#{<<"resend_after_ms">> => 300})), 1784: ?cfgh(P ++ [max_retries], 3, T(#{<<"max_retries">> => 3})), 1785: ?errh(T(#{<<"enabled">> => <<"">>})), 1786: ?errh(T(#{<<"resend_after_ms">> => -1})), 1787: ?errh(T(#{<<"max_retries">> => -1})). 1788: 1789: global_distrib_required_opts() -> 1790: #{<<"global_host">> => <<"global.example.com">>, 1791: <<"local_host">> => <<"localhost">>}. 1792: 1793: global_distrib_expected_config() -> 1794: #{global_host => <<"global.example.com">>, 1795: local_host => <<"localhost">>, 1796: connections => global_distrib_expected_connections()}. 1797: 1798: global_distrib_expected_connections() -> 1799: config([modules, mod_global_distrib, connections], 1800: #{endpoints => [{"localhost", 5555}], 1801: advertised_endpoints => [{"localhost", 5555}], 1802: resolved_endpoints => [{{0, 0, 0, 0, 0, 0, 0, 1}, 5555}, 1803: {{127, 0, 0, 1}, 5555}]}). 1804: 1805: mod_event_pusher_sns(_Config) -> 1806: RequiredOpts = #{<<"sns_host">> => <<"sns.eu-west-1.amazonaws.com">>, 1807: <<"region">> => <<"eu-west-1">>, 1808: <<"access_key_id">> => <<"AKIAIOSFODNN7EXAMPLE">>, 1809: <<"secret_access_key">> => <<"KEY">>, 1810: <<"account_id">> => <<"123456789012">>}, 1811: ExpectedCfg = #{sns_host => "sns.eu-west-1.amazonaws.com", 1812: region => "eu-west-1", 1813: access_key_id => "AKIAIOSFODNN7EXAMPLE", 1814: secret_access_key => "KEY", 1815: account_id => "123456789012"}, 1816: P = [modules, mod_event_pusher, sns], 1817: T = fun(Opts) -> #{<<"modules">> => 1818: #{<<"mod_event_pusher">> => #{<<"sns">> => Opts}}} 1819: end, 1820: ?cfgh(P, config(P, ExpectedCfg), T(RequiredOpts)), 1821: ?cfgh(P ++ [presence_updates_topic], "pres", 1822: T(RequiredOpts#{<<"presence_updates_topic">> => <<"pres">>})), 1823: ?cfgh(P ++ [pm_messages_topic], "pm", 1824: T(RequiredOpts#{<<"pm_messages_topic">> => <<"pm">>})), 1825: ?cfgh(P ++ [muc_messages_topic], "muc", 1826: T(RequiredOpts#{<<"muc_messages_topic">> => <<"muc">>})), 1827: ?cfgh(P ++ [plugin_module], mod_event_pusher_sns_defaults, 1828: T(RequiredOpts#{<<"plugin_module">> => <<"mod_event_pusher_sns_defaults">>})), 1829: ?cfgh(P ++ [pool_size], 10, 1830: T(RequiredOpts#{<<"pool_size">> => 10})), 1831: ?cfgh(P ++ [publish_retry_count], 1, 1832: T(RequiredOpts#{<<"publish_retry_count">> => 1})), 1833: ?cfgh(P ++ [publish_retry_time_ms], 100, 1834: T(RequiredOpts#{<<"publish_retry_time_ms">> => 100})), 1835: [?errh(T(maps:remove(Key, RequiredOpts))) || Key <- maps:keys(RequiredOpts)], 1836: [?errh(T(RequiredOpts#{Key => 1})) || Key <- maps:keys(RequiredOpts)], 1837: ?errh(T(RequiredOpts#{<<"presence_updates_topic">> => #{}})), 1838: ?errh(T(RequiredOpts#{<<"pm_messages_topic">> => true})), 1839: ?errh(T(RequiredOpts#{<<"muc_messages_topic">> => [1, 2]})), 1840: ?errh(T(RequiredOpts#{<<"plugin_module">> => <<"plug_and_play">>})), 1841: ?errh(T(RequiredOpts#{<<"pool_size">> => 0})), 1842: ?errh(T(RequiredOpts#{<<"publish_retry_count">> => -1})), 1843: ?errh(T(RequiredOpts#{<<"publish_retry_time_ms">> => -1})). 1844: 1845: mod_event_pusher_push(_Config) -> 1846: P = [modules, mod_event_pusher, push], 1847: T = fun(Opts) -> #{<<"modules">> => 1848: #{<<"mod_event_pusher">> => #{<<"push">> => Opts}}} 1849: end, 1850: ?cfgh(P, default_config(P), T(#{})), 1851: check_iqdisc(P, T), 1852: test_wpool(P ++ [wpool], fun(Opts) -> T(#{<<"wpool">> => Opts}) end), 1853: ?cfgh(P ++ [backend], rdbms, T(#{<<"backend">> => <<"rdbms">>})), 1854: ?cfgh(P ++ [plugin_module], mod_event_pusher_push_plugin_enhanced, 1855: T(#{<<"plugin_module">> => <<"mod_event_pusher_push_plugin_enhanced">>})), 1856: ?cfgh(P ++ [virtual_pubsub_hosts], [{fqdn, <<"host1">>}, {fqdn, <<"host2">>}], 1857: T(#{<<"virtual_pubsub_hosts">> => [<<"host1">>, <<"host2">>]})), 1858: ?cfgh(P ++ [virtual_pubsub_hosts], [{prefix, <<"pubsub.">>}, {prefix, <<"pub-sub.">>}], 1859: T(#{<<"virtual_pubsub_hosts">> => [<<"pubsub.@HOST@">>, <<"pub-sub.@HOST@">>]})), 1860: ?errh(T(#{<<"backend">> => <<"redis">>})), 1861: ?errh(T(#{<<"wpool">> => true})), 1862: ?errh(T(#{<<"plugin_module">> => <<"wow_cool_but_missing">>})), 1863: ?errh(T(#{<<"plugin_module">> => 1})), 1864: ?errh(T(#{<<"virtual_pubsub_hosts">> => [<<"host with whitespace">>]})), 1865: ?errh(T(#{<<"virtual_pubsub_hosts">> => [<<"invalid.sub@HOST@">>]})), 1866: ?errh(T(#{<<"virtual_pubsub_hosts">> => [<<"invalid.sub.@HOST@.as.well">>]})). 1867: 1868: test_wpool(P, T) -> 1869: ?cfgh(P, default_config(P), T(#{})), 1870: ?cfgh(P ++ [workers], 200, T(#{<<"workers">> => 200})), 1871: ?cfgh(P ++ [strategy], random_worker, T(#{<<"strategy">> => <<"random_worker">>})), 1872: ?cfgh(P ++ [call_timeout], 1000, T(#{<<"call_timeout">> => 1000})), 1873: ?errh(T(#{<<"workers">> => 0})), 1874: ?errh(T(#{<<"strategy">> => <<"worst_worker">>})), 1875: ?errh(T(#{<<"workers">> => 0})). 1876: 1877: mod_event_pusher_http(_Config) -> 1878: P = [modules, mod_event_pusher, http, handlers], 1879: T = fun(Handlers) -> #{<<"modules">> => 1880: #{<<"mod_event_pusher">> => 1881: #{<<"http">> => #{<<"handlers">> => Handlers}}}} 1882: end, 1883: DefaultHandler = mod_event_pusher_http_handler(), 1884: ?cfgh(P, [DefaultHandler], T([#{}])), 1885: ?cfgh(P, [DefaultHandler#{pool_name => my_pool}], 1886: T([#{<<"pool_name">> => <<"my_pool">>}])), 1887: ?cfgh(P, [DefaultHandler#{path => <<"notifications">>}], 1888: T([#{<<"path">> => <<"/notifications">>}])), 1889: ?cfgh(P, [DefaultHandler#{callback_module => mod_event_pusher_http}], % existing module 1890: T([#{<<"callback_module">> => <<"mod_event_pusher_http">>}])), 1891: ?cfgh(P, [DefaultHandler, DefaultHandler#{pool_name => my_pool}], % two handlers 1892: T([#{}, #{<<"pool_name">> => <<"my_pool">>}])), 1893: ?errh(T([#{<<"pool_name">> => <<>>}])), 1894: ?errh(T([#{<<"path">> => true}])), 1895: ?errh(T([#{<<"callback_module">> => <<"wow_cool_but_missing">>}])), 1896: ?errh(T([#{<<"callback_module">> => 1}])), 1897: ?errh(T([#{}, #{}])). % handlers have to be unique 1898: 1899: mod_event_pusher_rabbit(_Config) -> 1900: P = [modules, mod_event_pusher, rabbit], 1901: T = fun(Key, Opts) -> #{<<"modules">> => 1902: #{<<"mod_event_pusher">> => 1903: #{<<"rabbit">> => #{Key => Opts}}}} 1904: end, 1905: test_event_pusher_rabbit_exchange(P ++ [presence_exchange], 1906: fun(Opts) -> T(<<"presence_exchange">>, Opts) end), 1907: test_event_pusher_rabbit_msg_exchange(P ++ [chat_msg_exchange], 1908: fun(Opts) -> T(<<"chat_msg_exchange">>, Opts) end), 1909: test_event_pusher_rabbit_msg_exchange(P ++ [groupchat_msg_exchange], 1910: fun(Opts) -> T(<<"groupchat_msg_exchange">>, Opts) end). 1911: 1912: test_event_pusher_rabbit_msg_exchange(P, T) -> 1913: test_event_pusher_rabbit_exchange(P, T), 1914: ?cfgh(P, default_config(P), T(#{})), 1915: ?cfgh(P ++ [sent_topic], <<"outgoing">>, T(#{<<"sent_topic">> => <<"outgoing">>})), 1916: ?cfgh(P ++ [recv_topic], <<"incoming">>, T(#{<<"recv_topic">> => <<"incoming">>})), 1917: ?errh(T(#{<<"sent_topic">> => <<>>})), 1918: ?errh(T(#{<<"recv_topic">> => <<>>})). 1919: 1920: test_event_pusher_rabbit_exchange(P, T) -> 1921: ?cfgh(P, default_config(P), T(#{})), 1922: ?cfgh(P ++ [name], <<"notifications">>, T(#{<<"name">> => <<"notifications">>})), 1923: ?cfgh(P ++ [type], <<"direct">>, T(#{<<"type">> => <<"direct">>})), 1924: ?errh(T(#{<<"name">> => <<>>})), 1925: ?errh(T(#{<<"type">> => <<>>})). 1926: 1927: mod_http_upload(_Config) -> 1928: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_http_upload">> => Opts}} end, 1929: P = [modules, mod_http_upload], 1930: RequiredOpts = #{<<"s3">> => http_upload_s3_required_opts()}, 1931: S3Cfg = http_upload_s3_expected_cfg(), 1932: ?cfgh(P, mod_config(mod_http_upload, 1933: #{host => <<"upload.@HOST@">>, 1934: s3 => config_parser_helper:config([modules, mod_http_upload, s3], S3Cfg) 1935: }), 1936: T(RequiredOpts)), 1937: ?cfgh(P ++ [s3], S3Cfg#{add_acl => false}, T(RequiredOpts)), 1938: ?cfgh(P ++ [host], {prefix, <<"upload.">>}, 1939: T(RequiredOpts#{<<"host">> => <<"upload.@HOST@">>})), 1940: ?cfgh(P ++ [host], {fqdn, <<"upload.test">>}, 1941: T(RequiredOpts#{<<"host">> => <<"upload.test">>})), 1942: ?cfgh(P ++ [backend], s3, 1943: T(RequiredOpts#{<<"backend">> => <<"s3">>})), 1944: ?cfgh(P ++ [expiration_time], 666, 1945: T(RequiredOpts#{<<"expiration_time">> => 666})), 1946: ?cfgh(P ++ [token_bytes], 32, 1947: T(RequiredOpts#{<<"token_bytes">> => 32})), 1948: ?cfgh(P ++ [max_file_size], 42, 1949: T(RequiredOpts#{<<"max_file_size">> => 42})), 1950: ?errh(T(#{})), %% missing 's3' 1951: ?errh(T(RequiredOpts#{<<"backend">> => <<"">>})), 1952: ?errh(T(RequiredOpts#{<<"expiration_time">> => 0})), 1953: ?errh(T(RequiredOpts#{<<"token_bytes">> => 0})), 1954: ?errh(T(RequiredOpts#{<<"max_file_size">> => 0})), 1955: ?errh(T(RequiredOpts#{<<"host">> => <<"is this a host? no.">>})), 1956: ?errh(T(RequiredOpts#{<<"host">> => [<<"invalid.sub@HOST@">>]})), 1957: ?errh(T(RequiredOpts#{<<"host">> => [<<"invalid.sub.@HOST@.as.well">>]})), 1958: ?errh(T(RequiredOpts#{<<"host">> => [<<"not.supported.any.more.@HOSTS@">>]})), 1959: check_iqdisc(mod_http_upload, RequiredOpts). 1960: 1961: mod_http_upload_s3(_Config) -> 1962: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_http_upload">> => 1963: #{<<"s3">> => Opts}}} end, 1964: RequiredOpts = http_upload_s3_required_opts(), 1965: ExpectedCfg = http_upload_s3_expected_cfg(), 1966: P = [modules, mod_http_upload, s3], 1967: ?cfgh(P, ExpectedCfg#{add_acl => false}, T(RequiredOpts)), 1968: ?cfgh(P ++ [add_acl], true, T(RequiredOpts#{<<"add_acl">> => true})), 1969: [?errh(T(maps:remove(Key, RequiredOpts))) || Key <- maps:keys(RequiredOpts)], 1970: ?errh(T(RequiredOpts#{<<"bucket_url">> => <<>>})), 1971: ?errh(T(RequiredOpts#{<<"region">> => true})), 1972: ?errh(T(RequiredOpts#{<<"access_key_id">> => []})), 1973: ?errh(T(RequiredOpts#{<<"secret_access_key">> => 3})), 1974: ?errh(T(RequiredOpts#{<<"add_acl">> => <<"true">>})). 1975: 1976: http_upload_s3_required_opts() -> 1977: #{<<"bucket_url">> => <<"https://s3-eu-west-1.amazonaws.com/mybucket">>, 1978: <<"region">> => <<"antarctica-1">>, 1979: <<"access_key_id">> => <<"PLEASE">>, 1980: <<"secret_access_key">> => <<"ILOVEU">>}. 1981: 1982: http_upload_s3_expected_cfg() -> 1983: #{access_key_id => <<"PLEASE">>, 1984: bucket_url => <<"https://s3-eu-west-1.amazonaws.com/mybucket">>, 1985: region => <<"antarctica-1">>, 1986: secret_access_key => <<"ILOVEU">>}. 1987: 1988: mod_jingle_sip(_Config) -> 1989: check_module_defaults(mod_jingle_sip), 1990: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_jingle_sip">> => Opts}} end, 1991: P = [modules, mod_jingle_sip], 1992: ?cfgh(P ++ [proxy_host], "proxxxy.com", 1993: T(#{<<"proxy_host">> => <<"proxxxy.com">>})), 1994: ?cfgh(P ++ [proxy_port], 5601, 1995: T(#{<<"proxy_port">> => 5601})), 1996: ?cfgh(P ++ [listen_port], 5602, 1997: T(#{<<"listen_port">> => 5602})), 1998: ?cfgh(P ++ [local_host], "localhost", 1999: T(#{<<"local_host">> => <<"localhost">>})), 2000: ?cfgh(P ++ [sdp_origin], "127.0.0.1", 2001: T(#{<<"sdp_origin">> => <<"127.0.0.1">>})), 2002: ?cfgh(P ++ [transport], "tcp", 2003: T(#{<<"transport">> => <<"tcp">>})), 2004: ?cfgh(P ++ [username_to_phone], [{<<"2000006168">>, <<"+919177074440">>}], 2005: T(#{<<"username_to_phone">> => [#{<<"username">> => <<"2000006168">>, 2006: <<"phone">> => <<"+919177074440">>}]})), 2007: ?errh(T(#{<<"proxy_host">> => 1})), 2008: ?errh(T(#{<<"proxy_port">> => 1000000})), 2009: ?errh(T(#{<<"listen_port">> => -1})), 2010: ?errh(T(#{<<"local_host">> => <<>>})), 2011: ?errh(T(#{<<"sdp_origin">> => <<"abc">>})). 2012: 2013: mod_keystore(_Config) -> 2014: check_module_defaults(mod_keystore), 2015: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_keystore">> => Opts}} end, 2016: P = [modules, mod_keystore], 2017: ?cfgh(P ++ [ram_key_size], 1024, 2018: T(#{<<"ram_key_size">> => 1024})), 2019: ?errh(T(#{<<"ram_key_size">> => -1})). 2020: 2021: mod_keystore_keys(_Config) -> 2022: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_keystore">> => 2023: #{<<"keys">> => Opts}}} 2024: end, 2025: P = [modules, mod_keystore, keys], 2026: RequiredOpts = #{<<"name">> => <<"access_secret">>, 2027: <<"type">> => <<"ram">>}, 2028: ?cfgh(P ++ [access_secret], ram, 2029: T([RequiredOpts])), 2030: ?cfgh(P ++ [access_secret], {file, "priv/access_psk"}, 2031: T([RequiredOpts#{<<"type">> => <<"file">>, 2032: <<"path">> => <<"priv/access_psk">>}])), 2033: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2034: ?errh(T([RequiredOpts#{<<"name">> => <<>>}])), 2035: ?errh(T([RequiredOpts#{<<"type">> => <<"rampampam">>}])), 2036: ?errh(T([RequiredOpts#{<<"type">> => <<"file">>}])), 2037: ?errh(T([RequiredOpts#{<<"type">> => <<"file">>, 2038: <<"path">> => <<"does/not/exists">>}])), 2039: ?errh(T([#{<<"name">> => <<"same_name_twice">>, 2040: <<"type">> => <<"ram">>}, 2041: #{<<"name">> => <<"same_name_twice">>, 2042: <<"type">> => <<"file">>, 2043: <<"path">> => <<"priv/access_psk">>}])). 2044: 2045: mod_last(_Config) -> 2046: check_iqdisc(mod_last), 2047: check_module_defaults(mod_last), 2048: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_last">> => Opts}} end, 2049: P = [modules, mod_last], 2050: ?cfgh(P ++ [backend], mnesia, T(#{<<"backend">> => <<"mnesia">>})), 2051: ?cfgh(P ++ [backend], rdbms, T(#{<<"backend">> => <<"rdbms">>})), 2052: ?cfgh(P ++ [riak, bucket_type], <<"last">>, T(#{<<"backend">> => <<"riak">>})), 2053: ?cfgh(P ++ [riak, bucket_type], <<"test">>, 2054: T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"bucket_type">> => <<"test">>}})), 2055: ?errh(T(#{<<"backend">> => <<"frontend">>})), 2056: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})). 2057: 2058: mod_mam_meta(_Config) -> 2059: check_module_defaults(mod_mam_meta), 2060: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_mam_meta">> => Opts}} end, 2061: P = [modules, mod_mam_meta], 2062: test_cache_config(P ++ [cache], fun(Opts) -> T(#{<<"cache">> => Opts}) end), 2063: test_mod_mam_meta(P, T). 2064: 2065: mod_mam_meta_riak(_Config) -> 2066: T = fun(Opts) -> 2067: #{<<"modules">> => #{<<"mod_mam_meta">> => Opts#{<<"backend">> => <<"riak">>}}} 2068: end, 2069: P = [modules, mod_mam_meta, riak], 2070: ?cfgh(P, default_config([modules, mod_mam_meta, riak]), T(#{})), 2071: ?cfgh(P ++ [bucket_type], <<"mam_bucket">>, 2072: T(#{<<"riak">> => #{<<"bucket_type">> => <<"mam_bucket">>}})), 2073: ?cfgh(P ++ [search_index], <<"mam_index">>, 2074: T(#{<<"riak">> => #{<<"search_index">> => <<"mam_index">>}})), 2075: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => <<>>}})), 2076: ?errh(T(#{<<"riak">> => #{<<"search_index">> => <<>>}})). 2077: 2078: mod_mam_meta_pm(_Config) -> 2079: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_mam_meta">> => #{<<"pm">> => Opts}}} end, 2080: P = [modules, mod_mam_meta, pm], 2081: test_mod_mam_meta(P, T), 2082: ?cfgh(P, default_config(P), T(#{})), 2083: ?cfgh(P ++ [archive_groupchats], true, T(#{<<"archive_groupchats">> => true})), 2084: ?cfgh(P ++ [same_mam_id_for_peers], true, T(#{<<"same_mam_id_for_peers">> => true})), 2085: ?errh(T(#{<<"host">> => <<"muc.@HOST@">>})), % muc-only 2086: ?errh(T(#{<<"archive_groupchats">> => <<"not really">>})), 2087: ?errh(T(#{<<"same_mam_id_for_peers">> => <<"not really">>})). 2088: 2089: mod_mam_meta_muc(_Config) -> 2090: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_mam_meta">> => #{<<"muc">> => Opts}}} end, 2091: P = [modules, mod_mam_meta, muc], 2092: test_mod_mam_meta(P, T), 2093: ?cfgh(P, default_config(P), T(#{})), 2094: ?cfgh(P ++ [host], {prefix, <<"muc.">>}, T(#{<<"host">> => <<"muc.@HOST@">>})), 2095: ?cfgh(P ++ [host], {fqdn, <<"muc.test">>}, T(#{<<"host">> => <<"muc.test">>})), 2096: ?errh(T(#{<<"host">> => <<"is this a host? no.">>})), 2097: ?errh(T(#{<<"host">> => [<<"invalid.sub@HOST@">>]})), 2098: ?errh(T(#{<<"host">> => [<<"invalid.sub.@HOST@.as.well">>]})), 2099: ?errh(T(#{<<"archive_groupchats">> => true})), % pm-only 2100: ?errh(T(#{<<"same_mam_id_for_peers">> => true})). % pm-only 2101: 2102: test_mod_mam_meta(P, T) -> 2103: test_async_writer(P, T), 2104: ?cfgh(P ++ [backend], rdbms, 2105: T(#{<<"backend">> => <<"rdbms">>})), 2106: ?cfgh(P ++ [no_stanzaid_element], true, 2107: T(#{<<"no_stanzaid_element">> => true})), 2108: ?cfgh(P ++ [is_archivable_message], mod_mam_utils, 2109: T(#{<<"is_archivable_message">> => <<"mod_mam_utils">>})), 2110: ?cfgh(P ++ [archive_chat_markers], true, 2111: T(#{<<"archive_chat_markers">> => true})), 2112: ?cfgh(P ++ [message_retraction], false, 2113: T(#{<<"message_retraction">> => false})), 2114: ?cfgh(P ++ [user_prefs_store], rdbms, 2115: T(#{<<"user_prefs_store">> => <<"rdbms">>})), 2116: ?cfgh(P ++ [full_text_search], false, 2117: T(#{<<"full_text_search">> => false})), 2118: ?cfgh(P ++ [cache_users], false, 2119: T(#{<<"cache_users">> => false})), 2120: ?cfgh(P ++ [default_result_limit], 100, 2121: T(#{<<"default_result_limit">> => 100})), 2122: ?cfgh(P ++ [max_result_limit], 1000, 2123: T(#{<<"max_result_limit">> => 1000})), 2124: ?cfgh(P ++ [db_jid_format], mam_jid_rfc, 2125: T(#{<<"db_jid_format">> => <<"mam_jid_rfc">>})), 2126: ?cfgh(P ++ [db_message_format], mam_message_xml, 2127: T(#{<<"db_message_format">> => <<"mam_message_xml">>})), 2128: ?cfgh(P ++ [extra_fin_element], mod_mam_utils, 2129: T(#{<<"extra_fin_element">> => <<"mod_mam_utils">>})), 2130: ?cfgh(P ++ [extra_lookup_params], mod_mam_utils, 2131: T(#{<<"extra_lookup_params">> => <<"mod_mam_utils">>})), 2132: ?errh(T(#{<<"backend">> => <<"notepad">>})), 2133: ?errh(T(#{<<"no_stanzaid_element">> => <<"true">>})), 2134: ?errh(T(#{<<"is_archivable_message">> => <<"mod_mam_fake">>})), 2135: ?errh(T(#{<<"archive_chat_markers">> => <<"maybe">>})), 2136: ?errh(T(#{<<"message_retraction">> => 1})), 2137: ?errh(T(#{<<"user_prefs_store">> => <<"textfile">>})), 2138: ?errh(T(#{<<"full_text_search">> => <<"disabled">>})), 2139: ?errh(T(#{<<"cache_users">> => []})), 2140: ?errh(T(#{<<"default_result_limit">> => -1})), 2141: ?errh(T(#{<<"max_result_limit">> => -2})), 2142: ?errh(T(#{<<"db_jid_format">> => <<"not_a_module">>})), 2143: ?errh(T(#{<<"db_message_format">> => <<"not_a_module">>})), 2144: ?errh(T(#{<<"extra_fin_element">> => <<"bad_module">>})), 2145: ?errh(T(#{<<"extra_lookup_params">> => <<"bad_module">>})). 2146: 2147: test_cache_config(P, T) -> 2148: ?cfgh(P ++ [module], internal, T(#{<<"module">> => <<"internal">>})), 2149: ?cfgh(P ++ [time_to_live], 8600, T(#{<<"time_to_live">> => 8600})), 2150: ?cfgh(P ++ [time_to_live], infinity, T(#{<<"time_to_live">> => <<"infinity">>})), 2151: ?cfgh(P ++ [number_of_segments], 10, T(#{<<"number_of_segments">> => 10})), 2152: ?cfgh(P ++ [strategy], fifo, T(#{<<"strategy">> => <<"fifo">>})), 2153: ?errh(T(#{<<"module">> => <<"mod_wrong_cache">>})), 2154: ?errh(T(#{<<"time_to_live">> => 0})), 2155: ?errh(T(#{<<"strategy">> => <<"lifo">>})), 2156: ?errh(T(#{<<"number_of_segments">> => 0})), 2157: ?errh(T(#{<<"number_of_segments">> => <<"infinity">>})), 2158: ?errh(T(#{<<"cache">> => []})). 2159: 2160: test_async_writer(ParentP, ParentT) -> 2161: P = ParentP ++ [async_writer], 2162: T = fun(Opts) -> ParentT(#{<<"async_writer">> => Opts}) end, 2163: ?cfgh(P ++ [flush_interval], 1500, T(#{<<"flush_interval">> => 1500})), 2164: ?cfgh(P ++ [batch_size], 1500, T(#{<<"batch_size">> => 1500})), 2165: ?cfgh(P ++ [pool_size], 1500, T(#{<<"pool_size">> => 1500})), 2166: ?cfgh(P ++ [enabled], false, T(#{<<"enabled">> => false})), 2167: ?errh(T(#{<<"flush_interval">> => -1})), 2168: ?errh(T(#{<<"batch_size">> => -1})), 2169: ?errh(T(#{<<"pool_size">> => -1})), 2170: ?errh(T(#{<<"enabled">> => <<"wrong">>})). 2171: 2172: mod_muc(_Config) -> 2173: check_module_defaults(mod_muc), 2174: P = [modules, mod_muc], 2175: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_muc">> => #{K => V}}} end, 2176: ?cfgh(P ++ [host], {prefix, <<"conference.">>}, 2177: T(<<"host">>, <<"conference.@HOST@">>)), 2178: ?cfgh(P ++ [host], {fqdn, <<"conference.test">>}, 2179: T(<<"host">>, <<"conference.test">>)), 2180: ?cfgh(P ++ [backend], mnesia, T(<<"backend">>, <<"mnesia">>)), 2181: ?cfgh(P ++ [access], all, T(<<"access">>, <<"all">>)), 2182: ?cfgh(P ++ [access_create], admin, T(<<"access_create">>, <<"admin">>)), 2183: ?cfgh(P ++ [access_admin], none, T(<<"access_admin">>, <<"none">>)), 2184: ?cfgh(P ++ [access_persistent], all, T(<<"access_persistent">>, <<"all">>)), 2185: ?cfgh(P ++ [history_size], 20, T(<<"history_size">>, 20)), 2186: ?cfgh(P ++ [room_shaper], muc_room_shaper, 2187: T(<<"room_shaper">>, <<"muc_room_shaper">>)), 2188: ?cfgh(P ++ [max_room_id], infinity, T(<<"max_room_id">>, <<"infinity">>)), 2189: ?cfgh(P ++ [max_room_name], 30, T(<<"max_room_name">>, 30)), 2190: ?cfgh(P ++ [max_room_desc], 0, T(<<"max_room_desc">>, 0)), 2191: ?cfgh(P ++ [min_message_interval], 10, T(<<"min_message_interval">>, 10)), 2192: ?cfgh(P ++ [min_presence_interval], 0, T(<<"min_presence_interval">>, 0)), 2193: ?cfgh(P ++ [max_users], 30, T(<<"max_users">>, 30)), 2194: ?cfgh(P ++ [max_users_admin_threshold], 2, 2195: T(<<"max_users_admin_threshold">>, 2)), 2196: ?cfgh(P ++ [user_message_shaper], muc_msg_shaper, 2197: T(<<"user_message_shaper">>, <<"muc_msg_shaper">>)), 2198: ?cfgh(P ++ [user_presence_shaper], muc_pres_shaper, 2199: T(<<"user_presence_shaper">>, <<"muc_pres_shaper">>)), 2200: ?cfgh(P ++ [max_user_conferences], 10, T(<<"max_user_conferences">>, 10)), 2201: ?cfgh(P ++ [http_auth_pool], external_auth, 2202: T(<<"http_auth_pool">>, <<"external_auth">>)), 2203: ?cfgh(P ++ [load_permanent_rooms_at_startup], true, 2204: T(<<"load_permanent_rooms_at_startup">>, true)), 2205: ?cfgh(P ++ [hibernate_timeout], infinity, 2206: T(<<"hibernate_timeout">>, <<"infinity">>)), 2207: ?cfgh(P ++ [hibernated_room_check_interval], 5000, 2208: T(<<"hibernated_room_check_interval">>, 5000)), 2209: ?cfgh(P ++ [hibernated_room_timeout], 0, 2210: T(<<"hibernated_room_timeout">>, 0)), 2211: ?errh(T(<<"host">>, <<>>)), 2212: ?errh(T(<<"host">>, <<"is this a host? no.">>)), 2213: ?errh(T(<<"host">>, [<<"invalid.sub@HOST@">>])), 2214: ?errh(T(<<"host">>, [<<"invalid.sub.@HOST@.as.well">>])), 2215: ?errh(T(<<"backend">>, <<"amnesia">>)), 2216: ?errh(T(<<"access">>, <<>>)), 2217: ?errh(T(<<"access_create">>, 1)), 2218: ?errh(T(<<"access_admin">>, [])), 2219: ?errh(T(<<"access_persistent">>, true)), 2220: ?errh(T(<<"history_size">>, <<"20">>)), 2221: ?errh(T(<<"room_shaper">>, <<>>)), 2222: ?errh(T(<<"max_room_id">>, #{})), 2223: ?errh(T(<<"max_room_name">>, <<"infinite!">>)), 2224: ?errh(T(<<"max_room_desc">>, -1)), 2225: ?errh(T(<<"min_message_interval">>, -10)), 2226: ?errh(T(<<"min_presence_interval">>, <<"infinity">>)), 2227: ?errh(T(<<"max_users">>, 0)), 2228: ?errh(T(<<"max_users_admin_threshold">>, 0)), 2229: ?errh(T(<<"user_message_shaper">>, [])), 2230: ?errh(T(<<"user_presence_shaper">>, <<>>)), 2231: ?errh(T(<<"max_user_conferences">>, -1)), 2232: ?errh(T(<<"http_auth_pool">>, <<>>)), 2233: ?errh(T(<<"load_permanent_rooms_at_startup">>, <<"true">>)), 2234: ?errh(T(<<"hibernate_timeout">>, <<"really big">>)), 2235: ?errh(T(<<"hibernated_room_check_interval">>, -1)), 2236: ?errh(T(<<"hibernated_room_timeout">>, false)). 2237: 2238: mod_muc_default_room(_Config) -> 2239: P = [modules, mod_muc, default_room], 2240: T = fun(K, V) -> 2241: M = #{<<"mod_muc">> => #{<<"default_room">> => #{K => V}}}, 2242: #{<<"modules">> => M} 2243: end, 2244: ?cfgh(P ++ [title], <<"living room">>, T(<<"title">>, <<"living room">>)), 2245: ?cfgh(P ++ [description], <<"a room that is alive">>, 2246: T(<<"description">>, <<"a room that is alive">>)), 2247: ?cfgh(P ++ [allow_change_subj], true, T(<<"allow_change_subj">>, true)), 2248: ?cfgh(P ++ [allow_query_users], false, T(<<"allow_query_users">>, false)), 2249: ?cfgh(P ++ [allow_private_messages], true, 2250: T(<<"allow_private_messages">>, true)), 2251: ?cfgh(P ++ [allow_visitor_status], false, 2252: T(<<"allow_visitor_status">>, false)), 2253: ?cfgh(P ++ [allow_visitor_nickchange], true, 2254: T(<<"allow_visitor_nickchange">>, true)), 2255: ?cfgh(P ++ [public], false, T(<<"public">>, false)), 2256: ?cfgh(P ++ [public_list], true, T(<<"public_list">>, true)), 2257: ?cfgh(P ++ [persistent], true, T(<<"persistent">>, true)), 2258: ?cfgh(P ++ [moderated], false, T(<<"moderated">>, false)), 2259: ?cfgh(P ++ [members_by_default], true, T(<<"members_by_default">>, true)), 2260: ?cfgh(P ++ [members_only], false, T(<<"members_only">>, false)), 2261: ?cfgh(P ++ [allow_user_invites], true, T(<<"allow_user_invites">>, true)), 2262: ?cfgh(P ++ [allow_multiple_sessions], false, 2263: T(<<"allow_multiple_sessions">>, false)), 2264: ?cfgh(P ++ [password_protected], true, T(<<"password_protected">>, true)), 2265: ?cfgh(P ++ [password], <<"secret">>, T(<<"password">>, <<"secret">>)), 2266: ?cfgh(P ++ [anonymous], true, T(<<"anonymous">>, true)), 2267: ?cfgh(P ++ [max_users], 100, T(<<"max_users">>, 100)), 2268: ?cfgh(P ++ [logging], false, T(<<"logging">>, false)), 2269: ?cfgh(P ++ [maygetmemberlist], [moderator], 2270: T(<<"maygetmemberlist">>, [<<"moderator">>])), 2271: ?cfgh(P ++ [subject], <<"Lambda days">>, T(<<"subject">>, <<"Lambda days">>)), 2272: ?cfgh(P ++ [subject_author], <<"Alice">>, T(<<"subject_author">>, <<"Alice">>)), 2273: ?errh(T(<<"title">>, true)), 2274: ?errh(T(<<"description">>, 1)), 2275: ?errh(T(<<"allow_change_subj">>, <<"true">>)), 2276: ?errh(T(<<"allow_query_users">>, <<>>)), 2277: ?errh(T(<<"allow_private_messages">>, 1)), 2278: ?errh(T(<<"allow_visitor_status">>, [])), 2279: ?errh(T(<<"allow_visitor_nickchange">>, #{})), 2280: ?errh(T(<<"public">>, 0)), 2281: ?errh(T(<<"public_list">>, [false])), 2282: ?errh(T(<<"persistent">>, 1)), 2283: ?errh(T(<<"moderated">>, <<"yes">>)), 2284: ?errh(T(<<"members_by_default">>, 0)), 2285: ?errh(T(<<"members_only">>, [true])), 2286: ?errh(T(<<"allow_user_invites">>, <<>>)), 2287: ?errh(T(<<"allow_multiple_sessions">>, [])), 2288: ?errh(T(<<"password_protected">>, #{})), 2289: ?errh(T(<<"password">>, false)), 2290: ?errh(T(<<"anonymous">>, <<"maybe">>)), 2291: ?errh(T(<<"max_users">>, 0)), 2292: ?errh(T(<<"logging">>, [true, false])), 2293: ?errh(T(<<"maygetmemberlist">>, <<"moderator">>)), 2294: ?errh(T(<<"maygetmemberlist">>, [<<>>])), 2295: ?errh(T(<<"subject">>, [<<"subjective">>])), 2296: ?errh(T(<<"subject_author">>, 1)). 2297: 2298: mod_muc_default_room_affiliations(_Config) -> 2299: P = [modules, mod_muc, default_room, affiliations], 2300: T = fun(V) -> 2301: M = #{<<"mod_muc">> => #{<<"default_room">> => #{<<"affiliations">> => V}}}, 2302: #{<<"modules">> => M} 2303: end, 2304: RequiredOpts = #{<<"user">> => <<"alice">>, 2305: <<"server">> => <<"localhost">>, 2306: <<"resource">> => <<"phone">>, 2307: <<"affiliation">> => <<"moderator">>}, 2308: ExpectedCfg = {{<<"alice">>, <<"localhost">>, <<"phone">>}, moderator}, 2309: ?cfgh(P, [], T([])), 2310: ?cfgh(P, [ExpectedCfg], T([RequiredOpts])), 2311: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2312: ?errh(T([RequiredOpts#{<<"user">> := <<>>}])), 2313: ?errh(T([RequiredOpts#{<<"server">> := <<"domain? not really!">>}])), 2314: ?errh(T([RequiredOpts#{<<"resource">> := false}])), 2315: ?errh(T([RequiredOpts#{<<"affiliation">> := <<>>}])). 2316: 2317: mod_muc_log(_Config) -> 2318: check_module_defaults(mod_muc_log), 2319: P = [modules, mod_muc_log], 2320: T = fun(K, V) -> #{<<"modules">> => #{<<"mod_muc_log">> => #{K => V}}} end, 2321: ?cfgh(P ++ [outdir], "www/muc", T(<<"outdir">>, <<"www/muc">>)), 2322: ?cfgh(P ++ [access_log], muc_admin, T(<<"access_log">>, <<"muc_admin">>)), 2323: ?cfgh(P ++ [dirtype], subdirs, T(<<"dirtype">>, <<"subdirs">>)), 2324: ?cfgh(P ++ [dirname], room_name, T(<<"dirname">>, <<"room_name">>)), 2325: ?cfgh(P ++ [file_format], html, T(<<"file_format">>, <<"html">>)), 2326: ?cfgh(P ++ [css_file], <<"path/to/css_file">>, 2327: T(<<"css_file">>, <<"path/to/css_file">>)), 2328: ?cfgh(P ++ [timezone], local, T(<<"timezone">>, <<"local">>)), 2329: ?cfgh(P ++ [spam_prevention], false, T(<<"spam_prevention">>, false)), 2330: ?errh(T(<<"outdir">>, <<"does/not/exist">>)), 2331: ?errh(T(<<"access_log">>, 1)), 2332: ?errh(T(<<"dirtype">>, <<"imaginary">>)), 2333: ?errh(T(<<"dirname">>, <<"dyrektory">>)), 2334: ?errh(T(<<"file_format">>, <<"none">>)), 2335: ?errh(T(<<"css_file">>, <<>>)), 2336: ?errh(T(<<"timezone">>, <<"yes">>)), 2337: ?errh(T(<<"spam_prevention">>, <<"spam and eggs and spam">>)). 2338: 2339: mod_muc_log_top_link(_Config) -> 2340: P = [modules, mod_muc_log, top_link], 2341: T = fun(V) -> 2342: M = #{<<"mod_muc_log">> => #{<<"top_link">> => V}}, 2343: #{<<"modules">> => M} 2344: end, 2345: RequiredOpts = #{<<"target">> => <<"https://esl.github.io/MongooseDocs/">>, 2346: <<"text">> => <<"Docs">>}, 2347: ExpectedCfg = {"https://esl.github.io/MongooseDocs/", "Docs"}, 2348: ?cfgh(P, ExpectedCfg, T(RequiredOpts)), 2349: [?errh(T(maps:remove(K, RequiredOpts))) || K <- maps:keys(RequiredOpts)], 2350: ?errh(T(RequiredOpts#{<<"target">> => true})), 2351: ?errh(T(RequiredOpts#{<<"text">> => <<"">>})). 2352: 2353: mod_muc_light(_Config) -> 2354: check_module_defaults(mod_muc_light), 2355: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_muc_light">> => Opts}} end, 2356: P = [modules, mod_muc_light], 2357: test_cache_config(P ++ [cache_affs], fun(Opts) -> T(#{<<"cache_affs">> => Opts}) end), 2358: ?cfgh(P ++ [backend], mnesia, 2359: T(#{<<"backend">> => <<"mnesia">>})), 2360: ?cfgh(P ++ [host], {prefix, <<"muclight.">>}, 2361: T(#{<<"host">> => <<"muclight.@HOST@">>})), 2362: ?cfgh(P ++ [host], {fqdn, <<"muclight.test">>}, 2363: T(#{<<"host">> => <<"muclight.test">>})), 2364: ?cfgh(P ++ [equal_occupants], true, 2365: T(#{<<"equal_occupants">> => true})), 2366: ?cfgh(P ++ [legacy_mode], false, 2367: T(#{<<"legacy_mode">> => false})), 2368: ?cfgh(P ++ [rooms_per_user], 100, 2369: T(#{<<"rooms_per_user">> => 100})), 2370: ?cfgh(P ++ [blocking], false, 2371: T(#{<<"blocking">> => false})), 2372: ?cfgh(P ++ [all_can_configure], true, 2373: T(#{<<"all_can_configure">> => true})), 2374: ?cfgh(P ++ [all_can_invite], false, 2375: T(#{<<"all_can_invite">> => false})), 2376: ?cfgh(P ++ [max_occupants], infinity, 2377: T(#{<<"max_occupants">> => <<"infinity">>})), 2378: ?cfgh(P ++ [rooms_per_page], 10, 2379: T(#{<<"rooms_per_page">> => 10})), 2380: ?cfgh(P ++ [rooms_in_rosters], true, 2381: T(#{<<"rooms_in_rosters">> => true})), 2382: ?errh(T(#{<<"backend">> => <<"frontend">>})), 2383: ?errh(T(#{<<"host">> => <<"what is a domain?!">>})), 2384: ?errh(T(#{<<"host">> => [<<"invalid.sub@HOST@">>]})), 2385: ?errh(T(#{<<"host">> => [<<"invalid.sub.@HOST@.as.well">>]})), 2386: ?errh(T(#{<<"equal_occupants">> => <<"true">>})), 2387: ?errh(T(#{<<"legacy_mode">> => 1234})), 2388: ?errh(T(#{<<"rooms_per_user">> => 0})), 2389: ?errh(T(#{<<"blocking">> => <<"true">>})), 2390: ?errh(T(#{<<"all_can_configure">> => []})), 2391: ?errh(T(#{<<"all_can_invite">> => #{}})), 2392: ?errh(T(#{<<"max_occupants">> => <<"seven">>})), 2393: ?errh(T(#{<<"rooms_per_page">> => false})), 2394: ?errh(T(#{<<"rooms_in_rosters">> => [1, 2, 3]})). 2395: 2396: mod_muc_light_config_schema(_Config) -> 2397: T = fun(Opts) -> #{<<"modules">> => 2398: #{<<"mod_muc_light">> => #{<<"config_schema">> => Opts}}} end, 2399: P = [modules, mod_muc_light, config_schema], 2400: Field = #{<<"field">> => <<"my_field">>}, 2401: ?cfgh(P, [], T([])), 2402: ?cfgh(P, [{<<"my_field">>, <<"My Room">>, my_field, binary}], 2403: T([Field#{<<"string_value">> => <<"My Room">>}])), 2404: ?cfgh(P, [{<<"my_field">>, 1, my_field, integer}], 2405: T([Field#{<<"integer_value">> => 1}])), 2406: ?cfgh(P, [{<<"my_field">>, 0.5, my_field, float}], 2407: T([Field#{<<"float_value">> => 0.5}])), 2408: ?cfgh(P, [{<<"my_field">>, 0, your_field, integer}], 2409: T([Field#{<<"integer_value">> => 0, 2410: <<"internal_key">> => <<"your_field">>}])), 2411: ?cfgh(P, [{<<"żółć"/utf8>>, <<"Рентгеноэлектрокардиографический"/utf8>>, 'żółć', binary}], 2412: T([#{<<"field">> => <<"żółć"/utf8>>, 2413: <<"string_value">> => <<"Рентгеноэлектрокардиографический"/utf8>>}])), 2414: ?cfgh(P, [{<<"first">>, 1, first, integer}, % the config is u-key-sorted 2415: {<<"second">>, <<"two">>, second, binary}], 2416: T([#{<<"field">> => <<"second">>, <<"string_value">> => <<"two">>}, 2417: #{<<"field">> => <<"second">>, <<"float_value">> => 2.0}, 2418: #{<<"field">> => <<"first">>, <<"integer_value">> => 1}])), 2419: ?errh(T([#{<<"string_value">> => <<"My Room">>}])), 2420: ?errh(T([#{<<"field">> => <<>>, 2421: <<"string_value">> => <<"My Room">>}])), 2422: ?errh(T([Field#{<<"string_value">> => 0}])), 2423: ?errh(T([Field#{<<"integer_value">> => 1.5}])), 2424: ?errh(T([Field#{<<"float_value">> => 1}])), 2425: ?errh(T([Field#{<<"integer_value">> => 0, 2426: <<"string_value">> => <<"My Room">>}])), 2427: ?errh(T([Field#{<<"integer_value">> => 0, 2428: <<"internal_key">> => <<>>}])). 2429: 2430: mod_offline(_Config) -> 2431: check_module_defaults(mod_offline), 2432: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_offline">> => Opts}} end, 2433: P = [modules, mod_offline], 2434: ?cfgh(P ++ [access_max_user_messages], custom_max_user_offline_messages, 2435: T(#{<<"access_max_user_messages">> => <<"custom_max_user_offline_messages">>})), 2436: ?cfgh(P ++ [backend], rdbms, 2437: T(#{<<"backend">> => <<"rdbms">>})), 2438: ?cfgh(P ++ [riak, bucket_type], <<"test">>, 2439: T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"bucket_type">> => <<"test">>}})), 2440: ?errh(T(#{<<"access_max_user_messages">> => 1})), 2441: ?errh(T(#{<<"backend">> => <<"riak_is_the_best">>})), 2442: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})), 2443: ?errh(T(#{<<"riak">> => #{<<"bucket">> => <<"leaky">>}})). 2444: 2445: mod_offline_chatmarkers(_Config) -> 2446: check_module_defaults(mod_offline_chatmarkers), 2447: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_offline_chatmarkers">> => Opts}} end, 2448: P = [modules, mod_offline_chatmarkers], 2449: ?cfgh(P ++ [backend], rdbms, 2450: T(#{<<"backend">> => <<"rdbms">>})), 2451: ?cfgh(P ++ [store_groupchat_messages], true, 2452: T(#{<<"store_groupchat_messages">> => true})), 2453: ?errh(T(#{<<"store_groupchat_messages">> => 1})), 2454: ?errh(T(#{<<"backend">> => <<"riak_is_the_best">>})). 2455: 2456: mod_ping(_Config) -> 2457: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_ping">> => Opts}} end, 2458: P = [modules, mod_ping], 2459: check_iqdisc(mod_ping), 2460: check_module_defaults(mod_ping), 2461: ?cfgh(P ++ [send_pings], true, 2462: T(#{<<"send_pings">> => true})), 2463: ?cfgh(P ++ [ping_interval], timer:seconds(10), 2464: T(#{<<"ping_interval">> => 10})), 2465: ?cfgh(P ++ [timeout_action], kill, 2466: T(#{<<"timeout_action">> => <<"kill">>})), 2467: ?cfgh(P ++ [ping_req_timeout], timer:seconds(20), 2468: T(#{<<"ping_req_timeout">> => 20})), 2469: ?errh(T(#{<<"send_pings">> => 1})), 2470: ?errh(T(#{<<"ping_interval">> => 0})), 2471: ?errh(T(#{<<"timeout_action">> => <<"kill_them_all">>})), 2472: ?errh(T(#{<<"ping_req_timeout">> => 0})). 2473: 2474: mod_privacy(_Config) -> 2475: test_privacy_opts(mod_privacy). 2476: 2477: test_privacy_opts(Module) -> 2478: T = fun(Opts) -> #{<<"modules">> => #{atom_to_binary(Module) => Opts}} end, 2479: P = [modules, Module], 2480: check_module_defaults(Module), 2481: ?cfgh(P ++ [backend], mnesia, 2482: T(#{<<"backend">> => <<"mnesia">>})), 2483: ?cfgh(P ++ [riak, defaults_bucket_type], <<"defaults">>, 2484: T(#{<<"backend">> => <<"riak">>, 2485: <<"riak">> => #{<<"defaults_bucket_type">> => <<"defaults">>}})), 2486: ?cfgh(P ++ [riak, names_bucket_type], <<"names">>, 2487: T(#{<<"backend">> => <<"riak">>, 2488: <<"riak">> => #{<<"names_bucket_type">> => <<"names">>}})), 2489: ?cfgh(P ++ [riak, bucket_type], <<"bucket">>, 2490: T(#{<<"backend">> => <<"riak">>, 2491: <<"riak">> => #{<<"bucket_type">> => <<"bucket">>}})), 2492: ?cfgh(P ++ [riak], 2493: default_config([modules, mod_privacy, riak]), 2494: T(#{<<"backend">> => <<"riak">>})), 2495: ?errh(T(#{<<"backend">> => <<"mongoddt">>})), 2496: ?errh(T(#{<<"riak">> => #{<<"defaults_bucket_type">> => <<>>}})), 2497: ?errh(T(#{<<"riak">> => #{<<"names_bucket_type">> => 1}})), 2498: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})). 2499: 2500: mod_private(_Config) -> 2501: check_iqdisc(mod_private), 2502: check_module_defaults(mod_private), 2503: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_private">> => Opts}} end, 2504: P = [modules, mod_private], 2505: ?cfgh(P ++ [backend], riak, T(#{<<"backend">> => <<"riak">>})), 2506: ?cfgh(P ++ [riak, bucket_type], <<"private">>, T(#{<<"backend">> => <<"riak">>})), 2507: ?cfgh(P ++ [riak, bucket_type], <<"private_stuff">>, T(#{<<"backend">> => <<"riak">>, 2508: <<"riak">> => #{<<"bucket_type">> => <<"private_stuff">>}})), 2509: ?errh(T(#{<<"backend">> => <<"mssql">>})), 2510: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})). 2511: 2512: mod_pubsub(_Config) -> 2513: check_iqdisc(mod_pubsub), 2514: check_module_defaults(mod_pubsub), 2515: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_pubsub">> => Opts}} end, 2516: P = [modules, mod_pubsub], 2517: ?cfgh(P ++ [host], {prefix, <<"pubsub.">>}, 2518: T(#{<<"host">> => <<"pubsub.@HOST@">>})), 2519: ?cfgh(P ++ [host], {fqdn, <<"pubsub.test">>}, 2520: T(#{<<"host">> => <<"pubsub.test">>})), 2521: ?cfgh(P ++ [backend], rdbms, 2522: T(#{<<"backend">> => <<"rdbms">>})), 2523: ?cfgh(P ++ [access], all, 2524: T(#{<<"access_createnode">> => <<"all">>})), 2525: ?cfgh(P ++ [max_items_node], 20, 2526: T(#{<<"max_items_node">> => 20})), 2527: ?cfgh(P ++ [max_subscriptions_node], 30, 2528: T(#{<<"max_subscriptions_node">> => 30})), 2529: ?cfgh(P ++ [nodetree], nodetree_tree, 2530: T(#{<<"nodetree">> => <<"tree">>})), 2531: ?cfgh(P ++ [ignore_pep_from_offline], false, 2532: T(#{<<"ignore_pep_from_offline">> => false})), 2533: ?cfgh(P ++ [last_item_cache], rdbms, 2534: T(#{<<"last_item_cache">> => <<"rdbms">>})), 2535: ?cfgh(P ++ [plugins], [<<"flat">>, <<"dag">>], 2536: T(#{<<"plugins">> => [<<"flat">>, <<"dag">>]})), 2537: ?cfgh(P ++ [item_publisher], true, 2538: T(#{<<"item_publisher">> => true})), 2539: ?cfgh(P ++ [sync_broadcast], false, 2540: T(#{<<"sync_broadcast">> => false})), 2541: ?errh(T(#{<<"host">> => <<"">>})), 2542: ?errh(T(#{<<"host">> => <<"is this a host? no.">>})), 2543: ?errh(T(#{<<"host">> => [<<"invalid.sub@HOST@">>]})), 2544: ?errh(T(#{<<"host">> => [<<"invalid.sub.@HOST@.as.well">>]})), 2545: ?errh(T(#{<<"backend">> => <<"amnesia">>})), 2546: ?errh(T(#{<<"access_createnode">> => <<"">>})), 2547: ?errh(T(#{<<"max_items_node">> => -1})), 2548: ?errh(T(#{<<"max_subscriptions_node">> => 3.1415})), 2549: ?errh(T(#{<<"nodetree">> => <<"christmas_tree">>})), 2550: ?errh(T(#{<<"ignore_pep_from_offline">> => <<"maybe">>})), 2551: ?errh(T(#{<<"last_item_cache">> => false})), 2552: ?errh(T(#{<<"plugins">> => [<<"deep">>]})), 2553: ?errh(T(#{<<"item_publisher">> => 1})), 2554: ?errh(T(#{<<"sync_broadcast">> => []})). 2555: 2556: mod_pubsub_pep_mapping(_Config) -> 2557: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_pubsub">> => 2558: #{<<"pep_mapping">> => Opts}}} end, 2559: P = [modules, mod_pubsub, pep_mapping], 2560: RequiredOpts = #{<<"namespace">> => <<"urn:xmpp:microblog:0">>, 2561: <<"node">> => <<"mb">>}, 2562: ?cfgh(P ++ [<<"urn:xmpp:microblog:0">>], <<"mb">>, 2563: T([RequiredOpts])), 2564: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2565: [?errh(T([RequiredOpts#{Key => <<>>}])) || Key <- maps:keys(RequiredOpts)]. 2566: 2567: mod_pubsub_default_node_config(_Config) -> 2568: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_pubsub">> => 2569: #{<<"default_node_config">> => Opts}}} end, 2570: P = [modules, mod_pubsub, default_node_config], 2571: ?cfgh(P, [{access_model, open}], 2572: T(#{<<"access_model">> => <<"open">>})), 2573: ?cfgh(P, [{deliver_notifications, true}], 2574: T(#{<<"deliver_notifications">> => true})), 2575: ?cfgh(P, [{deliver_payloads, false}], 2576: T(#{<<"deliver_payloads">> => false})), 2577: ?cfgh(P, [{max_items, 1000}], 2578: T(#{<<"max_items">> => 1000})), 2579: ?cfgh(P, [{max_payload_size, 1000}], 2580: T(#{<<"max_payload_size">> => 1000})), 2581: ?cfgh(P, [{node_type, dag}], 2582: T(#{<<"node_type">> => <<"dag">>})), 2583: ?cfgh(P, [{notification_type, headline}], 2584: T(#{<<"notification_type">> => <<"headline">>})), 2585: ?cfgh(P, [{notify_config, true}], 2586: T(#{<<"notify_config">> => true})), 2587: ?cfgh(P, [{notify_delete, false}], 2588: T(#{<<"notify_delete">> => false})), 2589: ?cfgh(P, [{notify_retract, true}], 2590: T(#{<<"notify_retract">> => true})), 2591: ?cfgh(P, [{persist_items, false}], 2592: T(#{<<"persist_items">> => false})), 2593: ?cfgh(P, [{presence_based_delivery, true}], 2594: T(#{<<"presence_based_delivery">> => true})), 2595: ?cfgh(P, [{publish_model, open}], 2596: T(#{<<"publish_model">> => <<"open">>})), 2597: ?cfgh(P, [{purge_offline, false}], 2598: T(#{<<"purge_offline">> => false})), 2599: ?cfgh(P, [{roster_groups_allowed, [<<"friends">>]}], 2600: T(#{<<"roster_groups_allowed">> => [<<"friends">>]})), 2601: ?cfgh(P, [{send_last_published_item, on_sub_and_presence}], 2602: T(#{<<"send_last_published_item">> => <<"on_sub_and_presence">>})), 2603: ?cfgh(P, [{subscribe, true}], 2604: T(#{<<"subscribe">> => true})), 2605: ?errh(T(#{<<"access_model">> => <<>>})), 2606: ?errh(T(#{<<"deliver_notifications">> => <<"yes">>})), 2607: ?errh(T(#{<<"deliver_payloads">> => 0})), 2608: ?errh(T(#{<<"max_items">> => -1})), 2609: ?errh(T(#{<<"max_payload_size">> => -1})), 2610: ?errh(T(#{<<"node_type">> => [<<"dag">>]})), 2611: ?errh(T(#{<<"notification_type">> => <<>>})), 2612: ?errh(T(#{<<"notify_config">> => <<"false">>})), 2613: ?errh(T(#{<<"notify_delete">> => [true]})), 2614: ?errh(T(#{<<"notify_retract">> => #{}})), 2615: ?errh(T(#{<<"persist_items">> => 1})), 2616: ?errh(T(#{<<"presence_based_delivery">> => []})), 2617: ?errh(T(#{<<"publish_model">> => <<"">>})), 2618: ?errh(T(#{<<"purge_offline">> => 1})), 2619: ?errh(T(#{<<"roster_groups_allowed">> => [<<>>]})), 2620: ?errh(T(#{<<"send_last_published_item">> => <<>>})), 2621: ?errh(T(#{<<"subscribe">> => <<"never">>})). 2622: 2623: mod_push_service_mongoosepush(_Config) -> 2624: check_module_defaults(mod_push_service_mongoosepush), 2625: P = [modules, mod_push_service_mongoosepush], 2626: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_push_service_mongoosepush">> => Opts}} end, 2627: ?cfgh(P ++ [pool_name], test_pool, 2628: T(#{<<"pool_name">> => <<"test_pool">>})), 2629: ?cfgh(P ++ [api_version], <<"v2">>, 2630: T(#{<<"api_version">> => <<"v2">>})), 2631: ?cfgh(P ++ [max_http_connections], 999, 2632: T(#{<<"max_http_connections">> => 999})), 2633: ?errh(T(#{<<"pool_name">> => 1})), 2634: ?errh(T(#{<<"api_version">> => <<"v4">>})), 2635: ?errh(T(#{<<"max_http_connections">> => -1})). 2636: 2637: mod_register(_Config) -> 2638: check_module_defaults(mod_register), 2639: check_iqdisc(mod_register), 2640: P = [modules, mod_register], 2641: ?cfgh(P ++ [access], register, 2642: ip_access_register(<<"127.0.0.1">>)), 2643: ?cfgh(P ++ [ip_access], [{allow, "127.0.0.0/8"}, 2644: {deny, "0.0.0.0"}], 2645: ip_access_register(<<"0.0.0.0">>)), 2646: ?cfgh(P ++ [ip_access], [{allow, "127.0.0.0/8"}, 2647: {deny, "0.0.0.4"}], 2648: ip_access_register(<<"0.0.0.4">>)), 2649: ?cfgh(P ++ [ip_access], [{allow, "127.0.0.0/8"}, 2650: {deny, "::1"}], 2651: ip_access_register(<<"::1">>)), 2652: ?cfgh(P ++ [ip_access], [{allow, "127.0.0.0/8"}, 2653: {deny, "::1/128"}], 2654: ip_access_register(<<"::1/128">>)), 2655: ?errh(invalid_ip_access_register()), 2656: ?errh(invalid_ip_access_register_ipv6()), 2657: ?errh(ip_access_register(<<"hello">>)), 2658: ?errh(ip_access_register(<<"0.d">>)), 2659: ?cfgh(P ++ [welcome_message], {"Subject", "Body"}, 2660: welcome_message()), 2661: %% List of jids 2662: ?cfgh(P ++ [registration_watchers], [<<"alice@bob">>, <<"ilovemongoose@help">>], 2663: registration_watchers([<<"alice@bob">>, <<"ilovemongoose@help">>])), 2664: ?errh(registration_watchers([<<"alice@bob">>, <<"jids@have@no@feelings!">>])), 2665: %% non-negative integer 2666: ?cfgh(P ++ [password_strength], 42, 2667: password_strength_register(42)), 2668: ?errh(password_strength_register(<<"42">>)), 2669: ?errh(password_strength_register(<<"strong">>)), 2670: ?errh(password_strength_register(-150)), 2671: ?errh(welcome_message(<<"Subject">>, 1)), 2672: ?errh(welcome_message(1, <<"Body">>)). 2673: 2674: welcome_message() -> 2675: welcome_message(<<"Subject">>, <<"Body">>). 2676: 2677: welcome_message(S, B) -> 2678: Opts = #{<<"welcome_message">> => #{<<"subject">> => S, <<"body">> => B}}, 2679: #{<<"modules">> => #{<<"mod_register">> => Opts}}. 2680: 2681: password_strength_register(Strength) -> 2682: Opts = #{<<"password_strength">> => Strength}, 2683: #{<<"modules">> => #{<<"mod_register">> => Opts}}. 2684: 2685: ip_access_register(Ip) -> 2686: Opts = #{<<"access">> => <<"register">>, 2687: <<"ip_access">> => 2688: [#{<<"address">> => <<"127.0.0.0/8">>, <<"policy">> => <<"allow">>}, 2689: #{<<"address">> => Ip, <<"policy">> => <<"deny">>}]}, 2690: #{<<"modules">> => #{<<"mod_register">> => Opts}}. 2691: 2692: invalid_ip_access_register() -> 2693: Opts = #{<<"access">> => <<"register">>, 2694: <<"ip_access">> => 2695: [#{<<"address">> => <<"127.0.0.0/8">>, <<"policy">> => <<"allawww">>}, 2696: #{<<"address">> => <<"8.8.8.8">>, <<"policy">> => <<"denyh">>}]}, 2697: #{<<"modules">> => #{<<"mod_register">> => Opts}}. 2698: 2699: invalid_ip_access_register_ipv6() -> 2700: Opts = #{<<"access">> => <<"register">>, 2701: <<"ip_access">> => 2702: [#{<<"address">> => <<"::1/129">>, <<"policy">> => <<"allow">>}]}, 2703: #{<<"modules">> => #{<<"mod_register">> => Opts}}. 2704: 2705: registration_watchers(JidBins) -> 2706: Opts = #{<<"registration_watchers">> => JidBins}, 2707: #{<<"modules">> => #{<<"mod_register">> => Opts}}. 2708: 2709: mod_roster(_Config) -> 2710: check_iqdisc(mod_roster), 2711: check_module_defaults(mod_roster), 2712: P = [modules, mod_roster], 2713: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_roster">> => Opts}} end, 2714: ?cfgh(P ++ [versioning], true, 2715: T(#{<<"versioning">> => true})), 2716: ?cfgh(P ++ [store_current_id], true, 2717: T(#{<<"store_current_id">> => true})), 2718: ?cfgh(P ++ [backend], rdbms, 2719: T(#{<<"backend">> => <<"rdbms">>})), 2720: ?cfgh(P ++ [riak], config_parser_helper:default_config(P ++ [riak]), 2721: T(#{<<"backend">> => <<"riak">>})), 2722: ?cfgh(P ++ [riak, bucket_type], <<"my_type">>, 2723: T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"bucket_type">> => <<"my_type">>}})), 2724: ?cfgh(P ++ [riak, version_bucket_type], <<"my_versions">>, 2725: T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"version_bucket_type">> => <<"my_versions">>}})), 2726: 2727: ?errh(T(#{<<"versioning">> => 1})), 2728: ?errh(T(#{<<"store_current_id">> => 1})), 2729: ?errh(T(#{<<"backend">> => 1})), 2730: ?errh(T(#{<<"backend">> => <<"iloveyou">>})), 2731: ?errh(T(#{<<"riak">> => #{<<"version_bucket_type">> => 1}})), 2732: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})). 2733: 2734: mod_shared_roster_ldap(_Config) -> 2735: check_module_defaults(mod_shared_roster_ldap), 2736: P = [modules, mod_shared_roster_ldap], 2737: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_shared_roster_ldap">> => Opts}} end, 2738: ?cfgh(P ++ [pool_tag], my_tag, 2739: T(#{<<"pool_tag">> => <<"my_tag">>})), 2740: ?cfgh(P ++ [base], <<"string">>, 2741: T(#{<<"base">> => <<"string">>})), 2742: ?cfgh(P ++ [deref], always, 2743: T(#{<<"deref">> => <<"always">>})), 2744: %% Options: attributes 2745: ?cfgh(P ++ [groupattr], <<"cn">>, 2746: T(#{<<"groupattr">> => <<"cn">>})), 2747: ?cfgh(P ++ [groupdesc], <<"default">>, 2748: T(#{<<"groupdesc">> => <<"default">>})), 2749: ?cfgh(P ++ [userdesc], <<"cn">>, 2750: T(#{<<"userdesc">> => <<"cn">>})), 2751: ?cfgh(P ++ [useruid], <<"cn">>, 2752: T(#{<<"useruid">> => <<"cn">>})), 2753: ?cfgh(P ++ [memberattr], <<"memberUid">>, 2754: T(#{<<"memberattr">> => <<"memberUid">>})), 2755: ?cfgh(P ++ [memberattr_format], <<"%u">>, 2756: T(#{<<"memberattr_format">> => <<"%u">>})), 2757: ?cfgh(P ++ [memberattr_format_re], <<"">>, 2758: T(#{<<"memberattr_format_re">> => <<"">>})), 2759: %% Options: parameters 2760: ?cfgh(P ++ [auth_check], true, 2761: T(#{<<"auth_check">> => true})), 2762: ?cfgh(P ++ [user_cache_validity], 300, 2763: T(#{<<"user_cache_validity">> => 300})), 2764: ?cfgh(P ++ [group_cache_validity], 300, 2765: T(#{<<"group_cache_validity">> => 300})), 2766: ?cfgh(P ++ [user_cache_size], 300, 2767: T(#{<<"user_cache_size">> => 300})), 2768: ?cfgh(P ++ [group_cache_size], 300, 2769: T(#{<<"group_cache_size">> => 300})), 2770: %% Options: LDAP filters 2771: ?cfgh(P ++ [rfilter], <<"rfilter_test">>, 2772: T(#{<<"rfilter">> => <<"rfilter_test">>})), 2773: ?cfgh(P ++ [gfilter], <<"gfilter_test">>, 2774: T(#{<<"gfilter">> => <<"gfilter_test">>})), 2775: ?cfgh(P ++ [ufilter], <<"ufilter_test">>, 2776: T(#{<<"ufilter">> => <<"ufilter_test">>})), 2777: ?cfgh(P ++ [filter], <<"filter_test">>, 2778: T(#{<<"filter">> => <<"filter_test">>})), 2779: ?errh(T(#{<<"pool_tag">> => 1})), 2780: ?errh(T(#{<<"base">> => 1})), 2781: ?errh(T(#{<<"deref">> => 1})), 2782: %% Options: attributes 2783: ?errh(T(#{<<"groupattr">> => 1})), 2784: ?errh(T(#{<<"groupdesc">> => 1})), 2785: ?errh(T(#{<<"userdesc">> => 1})), 2786: ?errh(T(#{<<"useruid">> => 1})), 2787: ?errh(T(#{<<"memberattr">> => 1})), 2788: ?errh(T(#{<<"memberattr_format">> => 1})), 2789: ?errh(T(#{<<"memberattr_format_re">> => 1})), 2790: %% Options: parameters 2791: ?errh(T(#{<<"auth_check">> => 1})), 2792: ?errh(T(#{<<"user_cache_validity">> => -1})), 2793: ?errh(T(#{<<"group_cache_validity">> => -1})), 2794: ?errh(T(#{<<"user_cache_size">> => -1})), 2795: ?errh(T(#{<<"group_cache_size">> => -1})), 2796: %% Options: LDAP filters 2797: ?errh(T(#{<<"rfilter">> => 1})), 2798: ?errh(T(#{<<"gfilter">> => 1})), 2799: ?errh(T(#{<<"ufilter">> => 1})), 2800: ?errh(T(#{<<"filter">> => 1})). 2801: 2802: mod_sic(_Config) -> 2803: check_module_defaults(mod_sic), 2804: check_iqdisc(mod_sic). 2805: 2806: mod_smart_markers(_Config) -> 2807: check_module_defaults(mod_smart_markers), 2808: check_iqdisc(mod_smart_markers), 2809: P = [modules, mod_smart_markers], 2810: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_smart_markers">> => Opts}} end, 2811: ?cfgh(P ++ [backend], rdbms, T(#{<<"backend">> => <<"rdbms">>})), 2812: ?cfgh(P ++ [keep_private], true, T(#{<<"keep_private">> => true})), 2813: ?cfgh(P ++ [async_writer], #{pool_size => 8}, T(#{<<"async_writer">> => #{<<"pool_size">> => 8}})), 2814: ?errh(T(#{<<"backend">> => <<"nodejs">>})), 2815: ?errh(T(#{<<"keep_private">> => 1})). 2816: 2817: mod_stream_management(_Config) -> 2818: check_module_defaults(mod_stream_management), 2819: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_stream_management">> => Opts}} end, 2820: P = [modules, mod_stream_management], 2821: ?cfgh(P ++ [buffer_max], no_buffer, T(#{<<"buffer">> => false})), 2822: ?cfgh(P ++ [buffer_max], 10, T(#{<<"buffer_max">> => 10})), 2823: ?cfgh(P ++ [ack_freq], never, T(#{<<"ack">> => false})), 2824: ?cfgh(P ++ [ack_freq], 1, T(#{<<"ack_freq">> => 1})), 2825: ?cfgh(P ++ [resume_timeout], 999, T(#{<<"resume_timeout">> => 999})), 2826: 2827: ?errh(T(#{<<"buffer">> => 0})), 2828: ?errh(T(#{<<"buffer_max">> => -1})), 2829: ?errh(T(#{<<"ack">> => <<"false">>})), 2830: ?errh(T(#{<<"ack_freq">> => 0})), 2831: ?errh(T(#{<<"resume_timeout">> => true})), 2832: ?errh(T(#{<<"backend">> => <<"iloveyou">>})). 2833: 2834: mod_stream_management_stale_h(_Config) -> 2835: P = [modules, mod_stream_management, stale_h], 2836: T = fun(Opts) -> #{<<"modules">> => 2837: #{<<"mod_stream_management">> => #{<<"stale_h">> => Opts}}} end, 2838: ?cfgh(P ++ [enabled], true, T(#{<<"enabled">> => true})), 2839: ?cfgh(P ++ [repeat_after], 999, T(#{<<"repeat_after">> => 999})), 2840: ?cfgh(P ++ [geriatric], 999, T(#{<<"geriatric">> => 999})), 2841: ?cfgh(P, config_parser_helper:default_config(P), T(#{})), 2842: 2843: ?errh(T(#{<<"enabled">> => <<"true">>})), 2844: ?errh(T(#{<<"repeat_after">> => -1})), 2845: ?errh(T(#{<<"geriatric">> => <<"one">>})). 2846: 2847: mod_time(_Config) -> 2848: check_iqdisc(mod_time), 2849: check_module_defaults(mod_time). 2850: 2851: mod_vcard(_Config) -> 2852: check_module_defaults(mod_vcard), 2853: check_iqdisc(mod_vcard), 2854: P = [modules, mod_vcard], 2855: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_vcard">> => Opts}} end, 2856: ?cfgh(P ++ [iqdisc], one_queue, 2857: T(#{<<"iqdisc">> => #{<<"type">> => <<"one_queue">>}})), 2858: ?cfgh(P ++ [host], {prefix, <<"vjud.">>}, 2859: T(#{<<"host">> => <<"vjud.@HOST@">>})), 2860: ?cfgh(P ++ [host], {fqdn, <<"vjud.test">>}, 2861: T(#{<<"host">> => <<"vjud.test">>})), 2862: ?cfgh(P ++ [search], true, 2863: T(#{<<"search">> => true})), 2864: ?cfgh(P ++ [backend], mnesia, 2865: T(#{<<"backend">> => <<"mnesia">>})), 2866: ?cfgh(P ++ [matches], infinity, 2867: T(#{<<"matches">> => <<"infinity">>})), 2868: %% ldap 2869: ?cfgh(P ++ [ldap], config_parser_helper:default_config(P ++ [ldap]), 2870: T(#{<<"backend">> => <<"ldap">>})), 2871: ?cfgh(P ++ [ldap, pool_tag], my_tag, 2872: T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"pool_tag">> => <<"my_tag">>}})), 2873: ?cfgh(P ++ [ldap, base], <<"ou=Users,dc=ejd,dc=com">>, 2874: T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"base">> => <<"ou=Users,dc=ejd,dc=com">>}})), 2875: ?cfgh(P ++ [ldap, filter], <<"(&(objectClass=shadowAccount)(memberOf=Jabber Users))">>, 2876: T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"filter">> => <<"(&(objectClass=shadowAccount)(memberOf=Jabber Users))">>}})), 2877: ?cfgh(P ++ [ldap, deref], always, 2878: T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"deref">> => <<"always">>}})), 2879: ?cfgh(P ++ [ldap, search_operator], 'or', 2880: T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"search_operator">> => <<"or">>}})), 2881: ?cfgh(P ++ [ldap, binary_search_fields], [<<"PHOTO">>], 2882: T(#{<<"backend">> => <<"ldap">>, <<"ldap">> => #{<<"binary_search_fields">> => [<<"PHOTO">>]}})), 2883: %% riak 2884: ?cfgh(P ++ [riak, bucket_type], <<"vcard">>, 2885: T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"bucket_type">> => <<"vcard">>}})), 2886: ?cfgh(P ++ [riak, search_index], <<"vcard">>, 2887: T(#{<<"backend">> => <<"riak">>, <<"riak">> => #{<<"search_index">> => <<"vcard">>}})), 2888: 2889: ?errh(T(#{<<"host">> => 1})), 2890: ?errh(T(#{<<"host">> => <<"is this a host? no.">>})), 2891: ?errh(T(#{<<"host">> => [<<"invalid.sub@HOST@">>]})), 2892: ?errh(T(#{<<"host">> => [<<"invalid.sub.@HOST@.as.well">>]})), 2893: ?errh(T(#{<<"search">> => 1})), 2894: ?errh(T(#{<<"backend">> => <<"mememesia">>})), 2895: ?errh(T(#{<<"matches">> => -1})), 2896: %% ldap 2897: ?errh(T(#{<<"ldap_pool_tag">> => -1})), 2898: ?errh(T(#{<<"ldap_base">> => -1})), 2899: ?errh(T(#{<<"ldap_field">> => -1})), 2900: ?errh(T(#{<<"ldap_deref">> => <<"nevernever">>})), 2901: ?errh(T(#{<<"ldap_search_operator">> => <<"more">>})), 2902: ?errh(T(#{<<"ldap_binary_search_fields">> => [1]})), 2903: %% riak 2904: ?errh(T(#{<<"riak">> => #{<<"bucket_type">> => 1}})), 2905: ?errh(T(#{<<"riak">> => #{<<"search_index">> => 1}})). 2906: 2907: mod_vcard_ldap_uids(_Config) -> 2908: P = [modules, mod_vcard, ldap, uids], 2909: T = fun(Opts) -> #{<<"modules">> => 2910: #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, 2911: <<"ldap">> => #{<<"uids">> => Opts}}}} end, 2912: RequiredOpts = #{<<"attr">> => <<"name">>}, 2913: ExpectedCfg = <<"name">>, 2914: ?cfgh(P, [], T([])), 2915: ?cfgh(P, [ExpectedCfg], T([RequiredOpts])), 2916: ?cfgh(P, [{<<"name">>, <<"%u@mail.example.org">>}], 2917: T([RequiredOpts#{<<"format">> => <<"%u@mail.example.org">>}])), 2918: ?cfgh(P, [{<<"name">>, <<"%u@mail.example.org">>}, ExpectedCfg], 2919: T([RequiredOpts#{<<"format">> => <<"%u@mail.example.org">>}, RequiredOpts])), 2920: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2921: ?errh(T(RequiredOpts#{<<"attr">> := 1})), 2922: ?errh(T(RequiredOpts#{<<"format">> => true})). 2923: 2924: mod_vcard_ldap_vcard_map(_Config) -> 2925: P = [modules, mod_vcard, ldap, vcard_map], 2926: T = fun(Opts) -> #{<<"modules">> => 2927: #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, 2928: <<"ldap">> => #{<<"vcard_map">> => Opts}}}} end, 2929: RequiredOpts = #{<<"vcard_field">> => <<"FAMILY">>, 2930: <<"ldap_pattern">> => <<"%s">>, 2931: <<"ldap_field">> => <<"sn">>}, 2932: ExpectedCfg = {<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, 2933: ?cfgh(P, [], T([])), 2934: ?cfgh(P, [ExpectedCfg], T([RequiredOpts])), 2935: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2936: ?errh(T(RequiredOpts#{<<"vcard_field">> := false})), 2937: ?errh(T(RequiredOpts#{<<"ldap_pattern">> := false})), 2938: ?errh(T(RequiredOpts#{<<"ldap_field">> := -1})). 2939: 2940: mod_vcard_ldap_search_fields(_Config) -> 2941: P = [modules, mod_vcard, ldap, search_fields], 2942: T = fun(Opts) -> #{<<"modules">> => 2943: #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, 2944: <<"ldap">> => #{<<"search_fields">> => Opts}}}} end, 2945: RequiredOpts = #{<<"search_field">> => <<"Full Name">>, 2946: <<"ldap_field">> => <<"cn">>}, 2947: ExpectedCfg = {<<"Full Name">>, <<"cn">>}, 2948: ?cfgh(P, [], T([])), 2949: ?cfgh(P, [ExpectedCfg], T([RequiredOpts])), 2950: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2951: ?errh(T(RequiredOpts#{<<"search_field">> := false})), 2952: ?errh(T(RequiredOpts#{<<"ldap_field">> := -1})). 2953: 2954: mod_vcard_ldap_search_reported(_Config) -> 2955: P = [modules, mod_vcard, ldap, search_reported], 2956: T = fun(Opts) -> #{<<"modules">> => 2957: #{<<"mod_vcard">> => #{<<"backend">> => <<"ldap">>, 2958: <<"ldap">> => #{<<"search_reported">> => Opts}}}} end, 2959: RequiredOpts = #{<<"search_field">> => <<"Full Name">>, 2960: <<"vcard_field">> => <<"FN">>}, 2961: ExpectedCfg = {<<"Full Name">>, <<"FN">>}, 2962: ?cfgh(P, [], T([])), 2963: ?cfgh(P, [ExpectedCfg], T([RequiredOpts])), 2964: [?errh(T([maps:remove(Key, RequiredOpts)])) || Key <- maps:keys(RequiredOpts)], 2965: ?errh(T(RequiredOpts#{<<"search_field">> := false})), 2966: ?errh(T(RequiredOpts#{<<"vcard_field">> := -1})). 2967: 2968: mod_version(_Config) -> 2969: check_module_defaults(mod_version), 2970: check_iqdisc(mod_version), 2971: P = [modules, mod_version], 2972: T = fun(Opts) -> #{<<"modules">> => #{<<"mod_version">> => Opts}} end, 2973: ?cfgh(P ++ [os_info], true, T(#{<<"os_info">> => true})), 2974: ?errh(T(#{<<"os_info">> => 1})). 2975: 2976: modules_without_config(_Config) -> 2977: ?cfgh([modules, mod_amp], #{}, #{<<"modules">> => #{<<"mod_amp">> => #{}}}), 2978: ?errh(#{<<"modules">> => #{<<"mod_wrong">> => #{}}}). 2979: 2980: incorrect_module(_Config) -> 2981: ?errh(#{<<"modules">> => #{<<"mod_incorrect">> => #{}}}). 2982: 2983: %% Services 2984: 2985: service_admin_extra(_Config) -> 2986: P = [services, service_admin_extra], 2987: T = fun(Opts) -> #{<<"services">> => #{<<"service_admin_extra">> => Opts}} end, 2988: ?cfg(P, default_config(P), T(#{})), 2989: ?cfg(P ++ [submods], [node], T(#{<<"submods">> => [<<"node">>]})), 2990: ?err(T(#{<<"submods">> => 1})), 2991: ?err(T(#{<<"submods">> => [1]})), 2992: ?err(T(#{<<"submods">> => [<<"nodejshaha">>]})). 2993: 2994: service_domain_db(_Config) -> 2995: P = [services, service_domain_db], 2996: T = fun(Opts) -> #{<<"services">> => #{<<"service_domain_db">> => Opts}} end, 2997: ?cfg(P, default_config(P), T(#{})), 2998: ?cfg(P ++ [event_cleaning_interval], 1000, T(#{<<"event_cleaning_interval">> => 1000})), 2999: ?cfg(P ++ [event_max_age], 5000, T(#{<<"event_max_age">> => 5000})), 3000: ?cfg(P ++ [db_pool], my_pool, T(#{<<"db_pool">> => <<"my_pool">>})), 3001: ?err(T(#{<<"event_cleaning_interval">> => 0})), 3002: ?err(T(#{<<"event_max_age">> => 0})), 3003: ?err(T(#{<<"db_pool">> => 10})). 3004: 3005: service_mongoose_system_metrics(_Config) -> 3006: P = [services, service_mongoose_system_metrics], 3007: T = fun(Opts) -> #{<<"services">> => #{<<"service_mongoose_system_metrics">> => Opts}} end, 3008: ?cfg(P, default_config(P), T(#{})), 3009: ?cfg(P ++ [initial_report], 5000, T(#{<<"initial_report">> => 5000})), 3010: ?cfg(P ++ [periodic_report], 5000, T(#{<<"periodic_report">> => 5000})), 3011: ?cfg(P ++ [tracking_id], "UA-123456789", T(#{<<"tracking_id">> => <<"UA-123456789">>})), 3012: ?cfg(P ++ [report], true, T(#{<<"report">> => true})), 3013: ?err(T(#{<<"initial_report">> => <<"forever">>})), 3014: ?err(T(#{<<"periodic_report">> => <<"forever">>})), 3015: ?err(T(#{<<"initial_report">> => -1})), 3016: ?err(T(#{<<"periodic_report">> => -1})), 3017: ?err(T(#{<<"tracking_id">> => 666})), 3018: ?err(T(#{<<"report">> => <<"maybe">>})). 3019: 3020: %% Helpers for module tests 3021: 3022: check_iqdisc(Module) -> 3023: P = [modules, Module], 3024: T = fun(Opts) -> #{<<"modules">> => #{atom_to_binary(Module) => Opts}} end, 3025: check_iqdisc(P, T). 3026: 3027: check_iqdisc(Module, RequiredOpts) when is_map(RequiredOpts) -> 3028: P = [modules, Module], 3029: T = fun(Opts) -> 3030: #{<<"modules">> => #{atom_to_binary(Module) => maps:merge(RequiredOpts, Opts)}} 3031: end, 3032: check_iqdisc(P, T); 3033: check_iqdisc(ParentP, ParentT) when is_function(ParentT, 1) -> 3034: P = ParentP ++ [iqdisc], 3035: T = fun(Opts) -> ParentT(#{<<"iqdisc">> => Opts}) end, 3036: ?cfgh(P, {queues, 10}, T(#{<<"type">> => <<"queues">>, <<"workers">> => 10})), 3037: ?cfgh(P, parallel, T(#{<<"type">> => <<"parallel">>})), 3038: ?cfgh(P, one_queue, T(#{<<"type">> => <<"one_queue">>})), 3039: ?cfgh(P, no_queue, T(#{<<"type">> => <<"no_queue">>})), 3040: ?errh(T(#{<<"type">> => <<"one_queue_and_a_half">>})), 3041: ?errh(T(#{<<"type">> => <<"queues">>, <<"workers">> => 0})), 3042: ?errh(T(#{<<"type">> => <<"no_queue">>, <<"workers">> => 10})), 3043: ?errh(T(#{<<"workers">> => 10})). 3044: 3045: check_module_defaults(Mod) -> 3046: ExpectedCfg = default_mod_config(Mod), 3047: ?cfgh([modules, Mod], ExpectedCfg, #{<<"modules">> => #{atom_to_binary(Mod) => #{}}}). 3048: 3049: %% helpers for 'listen' tests 3050: 3051: listener(Type, Opts) -> 3052: config([listen, Type], Opts). 3053: 3054: http_handler_raw(Type, Opts) -> 3055: MergedOpts = maps:merge(#{<<"host">> => <<"localhost">>, <<"path">> => <<"/api">>}, Opts), 3056: listen_raw(http, #{<<"port">> => 5280, 3057: <<"handlers">> => #{atom_to_binary(Type) => [remove_undefined(MergedOpts)]}} 3058: ). 3059: 3060: listen_raw(Type, Opts) -> 3061: #{<<"listen">> => #{atom_to_binary(Type) => [remove_undefined(Opts)]}}. 3062: 3063: remove_undefined(M) -> 3064: maps:filter(fun(_, V) -> V =/= undefined end, M). 3065: 3066: %% helpers for 'auth' tests 3067: 3068: auth_ldap_raw(Opts) -> 3069: auth_raw(<<"ldap">>, Opts). 3070: 3071: auth_raw(Method, Opts) -> 3072: #{<<"auth">> => #{Method => Opts}}. 3073: 3074: %% helpers for 'pool' tests 3075: 3076: pool_config(PoolIn) -> 3077: Pool = merge_with_default_pool_config(PoolIn), 3078: [{outgoing_pools, [Pool]}]. 3079: 3080: pool_raw(Type, Tag, Opts) -> 3081: #{<<"outgoing_pools">> => #{Type => #{Tag => Opts}}}. 3082: 3083: pool_conn_raw(Type, Opts) -> 3084: #{<<"outgoing_pools">> => #{Type => #{<<"default">> => #{<<"connection">> => Opts}}}}. 3085: 3086: rdbms_opts() -> 3087: #{<<"driver">> => <<"pgsql">>, 3088: <<"host">> => <<"localhost">>, 3089: <<"database">> => <<"db">>, 3090: <<"username">> => <<"dbuser">>, 3091: <<"password">> => <<"secret">>}. 3092: 3093: %% helpers for 'access' tests 3094: 3095: access_raw(RuleName, RuleSpec) -> 3096: #{<<"access">> => #{RuleName => RuleSpec}}. 3097: 3098: %% helpers for 'host_config' tests 3099: 3100: host_config(Config) -> 3101: #{<<"host_config">> => [Config#{<<"host_type">> => ?HOST}]}. 3102: 3103: %% helpers for parsing 3104: 3105: -spec parse(map()) -> [mongoose_config_parser_toml:config()]. 3106: parse(M0) -> 3107: %% As 'hosts' (or 'host_types') and 'default_server_domain' options are mandatory, 3108: %% this function inserts them with dummy values if they are missing. 3109: %% To prevent the insertion, add a 'without' option to the map, e.g. without => [<<"hosts">>] 3110: %% The resulting map is then passed to the TOML config parser. 3111: M = maybe_insert_dummy_domain(M0), 3112: mongoose_config_parser:get_opts(mongoose_config_parser_toml:process(M)). 3113: 3114: maybe_insert_dummy_domain(M) -> 3115: DummyGenM = #{<<"default_server_domain">> => ?HOST, 3116: <<"hosts">> => [?HOST]}, 3117: {FilteredGenM, RawConfig} = case maps:take(without, M) of 3118: {Keys, Cfg} -> {maps:without(Keys, DummyGenM), Cfg}; 3119: error -> {DummyGenM, M} 3120: end, 3121: OldGenM = maps:get(<<"general">>, RawConfig, #{}), 3122: NewGenM = maps:merge(FilteredGenM, OldGenM), 3123: RawConfig#{<<"general">> => NewGenM}. 3124: 3125: %% helpers for testing individual options 3126: 3127: -spec host_opts([{key_prefix(), mongoose_config:value()}]) -> 3128: [{mongoose_config:key() | mongoose_config:key_path(), mongoose_config:value()}]. 3129: host_opts(ExpectedOptions) -> 3130: lists:map(fun({Key, Value}) -> {host_key(Key), Value} end, ExpectedOptions). 3131: 3132: %% @doc Build full per-host config key for host-or-global options 3133: -spec host_key(top_level_key_prefix()) -> mongoose_config:key(); 3134: (key_path_prefix()) -> mongoose_config:key_path(). 3135: host_key([TopKey | Rest]) when is_atom(TopKey) -> 3136: [{TopKey, ?HOST} | Rest]; 3137: host_key(Key) when is_atom(Key) -> 3138: {Key, ?HOST}. 3139: 3140: -spec assert_options([{mongoose_config:key() | mongoose_config:key_path(), mongoose_config:value()}], 3141: [mongoose_config_parser_toml:config()]) -> any(). 3142: assert_options(ExpectedOptions, Config) -> 3143: lists:foreach(fun({Key, Value}) -> assert_option(Key, Value, Config) end, ExpectedOptions). 3144: 3145: -spec assert_option(mongoose_config:key() | mongoose_config:key_path(), mongoose_config:value(), 3146: [mongoose_config_parser_toml:config()]) -> any(). 3147: assert_option(KeyPath, Value, Config) when is_list(KeyPath) -> 3148: compare_nodes(KeyPath, Value, get_config_value(KeyPath, Config)); 3149: assert_option(Key, Value, Config) -> 3150: assert_option([Key], Value, Config). 3151: 3152: -spec get_config_value(mongoose_config:key_path(), [mongoose_config_parser_toml:config()]) -> 3153: mongoose_config:value(). 3154: get_config_value([TopKey | Rest], Config) -> 3155: case lists:keyfind(TopKey, 1, Config) of 3156: false -> ct:fail({"option not found", TopKey, Config}); 3157: {_, TopValue} -> lists:foldl(fun get_value/2, TopValue, Rest) 3158: end. 3159: 3160: get_value(Index, List) when is_integer(Index), Index > 0, is_list(List) -> 3161: lists:nth(Index, List); 3162: get_value(Key, Map) when not is_integer(Key), is_map(Map) -> 3163: maps:get(Key, Map). 3164: 3165: %% helpers for file tests 3166: 3167: test_config_file(Config, File) -> 3168: OptionsPath = ejabberd_helper:data(Config, File ++ ".options"), 3169: ExpectedOpts = config_parser_helper:options(File), 3170: 3171: TOMLPath = ejabberd_helper:data(Config, File ++ ".toml"), 3172: State = mongoose_config_parser:parse_file(TOMLPath), 3173: TOMLOpts = mongoose_config_parser:get_opts(State), 3174: 3175: %% Save the parsed TOML options 3176: %% - for debugging 3177: %% - to update tests after a config change - always check the diff! 3178: save_opts(OptionsPath ++ ".parsed", TOMLOpts), 3179: compare_config(ExpectedOpts, TOMLOpts). 3180: 3181: save_opts(Path, Opts) -> 3182: FormattedOpts = [io_lib:format("~p.~n", [Opt]) || Opt <- lists:sort(Opts)], 3183: file:write_file(Path, FormattedOpts). 3184: 3185: compare_config(C1, C2) -> 3186: compare_unordered_lists(C1, C2, fun handle_config_option/2). 3187: 3188: handle_config_option({K1, V1}, {K2, V2}) -> 3189: ?eq(K1, K2), 3190: compare_nodes([K1], V1, V2); 3191: handle_config_option(Opt1, Opt2) -> 3192: ?eq(Opt1, Opt2). 3193: 3194: %% Comparisons for config options that have paths (top-level or nested in maps) 3195: 3196: -spec compare_nodes(mongoose_config:key_path(), mongoose_config:value(), mongoose_config:value()) -> 3197: any(). 3198: compare_nodes([listen], V1, V2) -> 3199: compare_ordered_lists(V1, V2, fun handle_listener/2); 3200: compare_nodes([outgoing_pools], V1, V2) -> 3201: compare_unordered_lists(V1, V2, fun handle_conn_pool/2); 3202: compare_nodes([{auth_method, _}], V1, V2) when is_atom(V1) -> 3203: ?eq([V1], V2); 3204: compare_nodes([{s2s_addr, _}], {_, _, _, _} = IP1, IP2) -> 3205: ?eq(inet:ntoa(IP1), IP2); 3206: compare_nodes(Node, V1, V2) when is_map(V1), is_map(V2) -> 3207: compare_maps(V1, V2, fun({K1, MV1}, {K2, MV2}) -> 3208: ?eq(K1, K2), 3209: compare_nodes(Node ++ [K1], MV1, MV2) 3210: end); 3211: compare_nodes(Node, V1, V2) -> 3212: ?eq({Node, V1}, {Node, V2}). 3213: 3214: %% Comparisons of internal config option parts 3215: 3216: handle_listener(V1, V2) -> 3217: ct:pal("Listeners: ~p~n~p", [V1,V2]), 3218: compare_maps(V1, V2, fun handle_listener_option/2). 3219: 3220: handle_listener_option({tls, O1}, {tls, O2}) -> 3221: compare_unordered_lists(O1, O2); 3222: handle_listener_option({handlers, M1}, {handlers, M2}) -> 3223: compare_ordered_lists(M1, M2, fun compare_maps/2); 3224: handle_listener_option(V1, V2) -> ?eq(V1, V2). 3225: 3226: handle_item_with_opts({M1, O1}, {M2, O2}) -> 3227: ?eq(M1, M2), 3228: compare_unordered_lists(O1, O2). 3229: 3230: handle_conn_pool(#{type := Type1, scope := Scope1, tag := Tag1, opts := POpts1, conn_opts := COpts1}, 3231: #{type := Type2, scope := Scope2, tag := Tag2, opts := POpts2, conn_opts := COpts2}) -> 3232: ?eq(Type1, Type2), 3233: ?eq(Scope1, Scope2), 3234: ?eq(Tag1, Tag2), 3235: compare_maps(POpts1, POpts2), 3236: compare_maps(COpts1, COpts2, fun handle_conn_opt/2). 3237: 3238: handle_conn_opt({server, {D1, H1, DB1, U1, P1, O1}}, 3239: {server, {D2, H2, DB2, U2, P2, O2}}) -> 3240: ?eq(D1, D2), 3241: ?eq(H1, H2), 3242: ?eq(DB1, DB2), 3243: ?eq(U1, U2), 3244: ?eq(P1, P2), 3245: compare_unordered_lists(O1, O2, fun handle_db_server_opt/2); 3246: handle_conn_opt({http_opts, O1}, {http_opts, O2}) -> 3247: compare_unordered_lists(O1, O2); 3248: handle_conn_opt(V1, V2) -> ?eq(V1, V2). 3249: 3250: handle_db_server_opt({ssl_opts, O1}, {ssl_opts, O2}) -> 3251: compare_unordered_lists(O1, O2); 3252: handle_db_server_opt(V1, V2) -> ?eq(V1, V2). 3253: 3254: %% Generic assertions, use the 'F' handler for any custom cases 3255: compare_unordered_lists(L1, L2) when is_list(L1), is_list(L2) -> 3256: compare_unordered_lists(L1, L2, fun(V1, V2) -> ?eq(V1, V2) end). 3257: 3258: compare_unordered_lists(L1, L2, F) when is_list(L1), is_list(L2) -> 3259: SL1 = lists:sort(L1), 3260: SL2 = lists:sort(L2), 3261: compare_ordered_lists(SL1, SL2, F). 3262: 3263: compare_ordered_lists([H1|T1], [H1|T2], F) -> 3264: compare_ordered_lists(T1, T2, F); 3265: compare_ordered_lists([H1|T1] = L1, [H2|T2] = L2, F) -> 3266: try F(H1, H2) 3267: catch error:R:S -> 3268: ct:fail({"Failed to compare ordered lists", L1, L2, R, S}) 3269: end, 3270: compare_ordered_lists(T1, T2, F); 3271: compare_ordered_lists([], [], _) -> 3272: ok. 3273: 3274: compare_maps(M1, M2) -> 3275: compare_maps(M1, M2, fun(V1, V2) -> ?eq(V1, V2) end). 3276: 3277: compare_maps(M1, M2, F) -> 3278: compare_unordered_lists(maps:to_list(M1), maps:to_list(M2), F). 3279: 3280: create_files(Config) -> 3281: %% The files must exist for validation to pass 3282: Root = small_path_helper:repo_dir(Config), 3283: file:make_dir("priv"), 3284: [ensure_copied(filename:join(Root, From), To) || {From, To} <- files_to_copy()], 3285: ok = file:write_file("priv/access_psk", ""), 3286: ok = file:write_file("priv/provision_psk", ""), 3287: ok = filelib:ensure_dir("www/muc/dummy"). 3288: 3289: ensure_copied(From, To) -> 3290: case file:copy(From, To) of 3291: {ok,_} -> 3292: ok; 3293: Other -> 3294: error(#{what => ensure_copied_failed, from => From, to => To, 3295: reason => Other}) 3296: end. 3297: 3298: files_to_copy() -> 3299: [{"tools/ssl/mongooseim/privkey.pem", "priv/dc1.pem"}, 3300: {"tools/ssl/mongooseim/cert.pem", "priv/cert.pem"}, 3301: {"tools/ssl/mongooseim/dh_server.pem", "priv/dh.pem"}, 3302: {"tools/ssl/mongooseim/server.pem", "priv/server.pem"}, 3303: {"tools/ssl/ca/cacert.pem", "priv/ca.pem"}].