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