diff --git a/test/README b/test/README index de1a96aa2..68ff183dc 100644 --- a/test/README +++ b/test/README @@ -1,9 +1,12 @@ -You need MySQL, PostgreSQL and Redis up and running. +You need MySQL, MSSQL, PostgreSQL and Redis up and running. MySQL should be accepting TCP connections on localhost:3306. +MSSQL should be accepting TCP connections on localhost:1433. PostgreSQL should be accepting TCP connections on localhost:5432. Redis should be accepting TCP connections on localhost:6379. MySQL and PostgreSQL should grant full access to user 'ejabberd_test' with password 'ejabberd_test' on database 'ejabberd_test'. +MSSQL should grant full access to user 'ejabberd_test' with +password 'ejabberd_Test1' on database 'ejabberd_test'. Here is a quick setup example: @@ -24,3 +27,23 @@ mysql> CREATE USER 'ejabberd_test'@'localhost' IDENTIFIED BY 'ejabberd_test'; mysql> CREATE DATABASE ejabberd_test; mysql> GRANT ALL ON ejabberd_test.* TO 'ejabberd_test'@'localhost'; $ mysql ejabberd_test < sql/mysql.sql + +------------------- + MS SQL Server +------------------- +$ sqlcmd -U SA -P ejabberd_Test1 -S localhost +1> CREATE DATABASE ejabberd_test; +2> GO +1> USE ejabberd_test; +2> GO +Changed database context to 'ejabberd_test'. +1> CREATE LOGIN ejabberd_test WITH PASSWORD = 'ejabberd_Test1'; +2> GO +1> CREATE USER ejabberd_test FOR LOGIN ejabberd_test; +2> GO +1> GRANT ALL TO ejabberd_test; +2> GO +The ALL permission is deprecated and maintained only for compatibility. It DOES NOT imply ALL permissions defined on the entity. +1> GRANT CONTROL ON SCHEMA ::dbo TO ejabberd_test; +2> GO +$ sqlcmd -U ejabberd_test -P ejabberd_Test1 -S localhost -d ejabberd_test -i sql/mssql.sql diff --git a/test/docker/README.md b/test/docker/README.md index 22324a6e0..24c675cab 100644 --- a/test/docker/README.md +++ b/test/docker/README.md @@ -4,7 +4,7 @@ You can start the Docker environment with Docker Compose, from ejabberd repository root. -The following command will launch MySQL, PostgreSQL, Redis and keep the console +The following command will launch MySQL, MSSQL, PostgreSQL, Redis and keep the console attached to it. ``` @@ -15,6 +15,17 @@ mkdir test/docker/db/postgres/data You can stop all the databases with CTRL-C. +## Creating database for MSSQL + +The following commands will create the necessary login, user and database, will grant rights on the database in MSSQL and create the ejabberd schema: + +``` +docker cp test/docker/db/mssql/initdb/initdb_mssql.sql ejabberd-mssql:/ +docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql +docker cp sql/mssql.sql ejabberd-mssql:/ +docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /mssql.sql +``` + ## Running tests Before running the test, you can ensure there is no running instance of Erlang common test tool. You can run the following @@ -43,4 +54,5 @@ If you want to clean the data, you can remove the data directories after the `do ``` rm -rf test/docker/db/mysql/data rm -rf test/docker/db/postgres/data +docker volume rm docker_mssqldata ``` diff --git a/test/docker/db/mssql/initdb/initdb_mssql.sql b/test/docker/db/mssql/initdb/initdb_mssql.sql new file mode 100644 index 000000000..a9ec5a5a8 --- /dev/null +++ b/test/docker/db/mssql/initdb/initdb_mssql.sql @@ -0,0 +1,23 @@ +USE [master] +GO + +IF DB_ID('ejabberd_test') IS NOT NULL + set noexec on -- prevent creation when already exists + +CREATE DATABASE ejabberd_test; +GO + +USE ejabberd_test; +GO + +CREATE LOGIN ejabberd_test WITH PASSWORD = 'ejabberd_Test1'; +GO + +CREATE USER ejabberd_test FOR LOGIN ejabberd_test; +GO + +GRANT ALL TO ejabberd_test; +GO + +GRANT CONTROL ON SCHEMA ::dbo TO ejabberd_test; +GO diff --git a/test/docker/docker-compose.yml b/test/docker/docker-compose.yml index f98612036..c6b800dad 100644 --- a/test/docker/docker-compose.yml +++ b/test/docker/docker-compose.yml @@ -17,6 +17,18 @@ services: MYSQL_USER: ejabberd_test MYSQL_PASSWORD: ejabberd_test + mssql: + image: mcr.microsoft.com/mssql/server + container_name: ejabberd-mssql + volumes: + - mssqldata:/var/opt/mssql + restart: always + ports: + - 1433:1433 + environment: + ACCEPT_EULA: Y + SA_PASSWORD: ejabberd_Test1 + postgres: image: postgres:latest container_name: ejabberd-postgres @@ -35,3 +47,6 @@ services: container_name: ejabberd-redis ports: - 6379:6379 + +volumes: + mssqldata: diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index e471823aa..5942b0020 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -77,11 +77,21 @@ init_per_group(Group, Config) -> do_init_per_group(Group, Config); Backends -> %% Skipped backends that were not explicitely enabled - case lists:member(Group, Backends) of - true -> + case Group of + mssql -> + case lists:member(odbc, Backends) of + true -> do_init_per_group(Group, Config); - false -> + false -> {skip, {disabled_backend, Group}} + end; + _ -> + case lists:member(Group, Backends) of + true -> + do_init_per_group(Group, Config); + false -> + {skip, {disabled_backend, Group}} + end end end end. @@ -104,6 +114,15 @@ do_init_per_group(mysql, Config) -> Err -> {skip, {mysql_not_available, Err}} end; +do_init_per_group(mssql, Config) -> + case catch ejabberd_sql:sql_query(?MSSQL_VHOST, [<<"select 1;">>]) of + {selected, _, _} -> + mod_muc:shutdown_rooms(?MSSQL_VHOST), + clear_sql_tables(mssql, ?config(base_dir, Config)), + set_opt(server, ?MSSQL_VHOST, Config); + Err -> + {skip, {mssql_not_available, Err}} + end; do_init_per_group(pgsql, Config) -> case catch ejabberd_sql:sql_query(?PGSQL_VHOST, [<<"select 1;">>]) of {selected, _, _} -> @@ -158,6 +177,8 @@ end_per_group(redis, _Config) -> ok; end_per_group(mysql, _Config) -> ok; +end_per_group(mssql, _Config) -> + ok; end_per_group(pgsql, _Config) -> ok; end_per_group(sqlite, _Config) -> @@ -486,6 +507,7 @@ groups() -> {mnesia, [sequence], db_tests(mnesia)}, {redis, [sequence], db_tests(redis)}, {mysql, [sequence], db_tests(mysql)}, + {mssql, [sequence], db_tests(mssql)}, {pgsql, [sequence], db_tests(pgsql)}, {sqlite, [sequence], db_tests(sqlite)}]. @@ -495,6 +517,7 @@ all() -> {group, mnesia}, {group, redis}, {group, mysql}, + {group, mssql}, {group, pgsql}, {group, sqlite}, {group, extauth}, @@ -1013,6 +1036,14 @@ clear_sql_tables(Type, BaseDir) -> "mysql.sql" end, {?MYSQL_VHOST, Path}; + mssql -> + Path = case ejabberd_sql:use_new_schema() of + true -> + "mssql.new.sql"; + false -> + "mssql.sql" + end, + {?MSSQL_VHOST, Path}; pgsql -> Path = case ejabberd_sql:use_new_schema() of true -> diff --git a/test/ejabberd_SUITE_data/ejabberd.cfg b/test/ejabberd_SUITE_data/ejabberd.cfg index a92608b60..f071ffe8b 100644 --- a/test/ejabberd_SUITE_data/ejabberd.cfg +++ b/test/ejabberd_SUITE_data/ejabberd.cfg @@ -2,6 +2,7 @@ {hosts, ["localhost", "mnesia.localhost", "mysql.localhost", + "mssql.localhost", "pgsql.localhost", "sqlite.localhost", "extauth.localhost", @@ -102,6 +103,27 @@ {mod_roster, [{db_type, odbc}]}, {mod_vcard, [{db_type, odbc}]}]} ]}. +{host_config, "mssql.localhost", + [{auth_method, odbc}, + {odbc_pool_size, 1}, + {odbc_server, {mssql, "localhost", "ejabberd_test", + "ejabberd_test", "ejabberd_Test1"}}, + {{add, modules}, [{mod_announce, [{db_type, odbc}]}, + {mod_blocking, [{db_type, odbc}]}, + {mod_caps, [{db_type, odbc}]}, + {mod_last, [{db_type, odbc}]}, + {mod_muc, [{db_type, odbc}]}, + {mod_offline, [{db_type, odbc}]}, + {mod_privacy, [{db_type, odbc}]}, + {mod_private, [{db_type, odbc}]}, + {mod_pubsub, [{db_type, odbc}, + {access_createnode, pubsub_createnode}, + {ignore_pep_from_offline, true}, + {last_item_cache, false}, + {plugins, ["flat", "hometree", "pep"]}]}, + {mod_roster, [{db_type, odbc}]}, + {mod_vcard, [{db_type, odbc}]}]} + ]}. {host_config, "pgsql.localhost", [{auth_method, odbc}, {odbc_pool_size, 1}, diff --git a/test/ejabberd_SUITE_data/ejabberd.mssql.yml b/test/ejabberd_SUITE_data/ejabberd.mssql.yml new file mode 100644 index 000000000..1ecf77ba8 --- /dev/null +++ b/test/ejabberd_SUITE_data/ejabberd.mssql.yml @@ -0,0 +1,71 @@ +define_macro: + MSSQL_CONFIG: + sql_username: MSSQL_USER + sql_type: mssql + sql_server: MSSQL_SERVER + sql_port: MSSQL_PORT + sql_pool_size: 1 + sql_password: MSSQL_PASS + sql_database: MSSQL_DB + auth_method: sql + sm_db_type: sql + modules: + mod_announce: + db_type: sql + access: local + mod_blocking: [] + mod_caps: + db_type: sql + mod_last: + db_type: sql + mod_muc: + db_type: sql + ram_db_type: sql + vcard: VCARD + mod_offline: + use_cache: true + db_type: sql + mod_privacy: + db_type: sql + mod_private: + db_type: sql + mod_pubsub: + db_type: sql + access_createnode: pubsub_createnode + ignore_pep_from_offline: true + last_item_cache: false + plugins: + - "flat" + - "pep" + vcard: VCARD + mod_roster: + versioning: true + store_current_id: true + db_type: sql + mod_mam: + db_type: sql + mod_vcard: + db_type: sql + vcard: VCARD + mod_vcard_xupdate: [] + mod_adhoc: [] + mod_configure: [] + mod_disco: [] + mod_ping: [] + mod_proxy65: [] + mod_push: + db_type: sql + include_body: false + mod_push_keepalive: [] + mod_s2s_dialback: [] + mod_stream_mgmt: + resume_timeout: 3 + mod_legacy_auth: [] + mod_register: + welcome_message: + subject: "Welcome!" + body: "Hi. +Welcome to this XMPP server." + mod_stats: [] + mod_time: [] + mod_version: [] diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 5f584b6da..8ae915e0b 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -4,6 +4,7 @@ include_config_file: - ejabberd.ldap.yml - ejabberd.mnesia.yml - ejabberd.mysql.yml + - ejabberd.mssql.yml - ejabberd.pgsql.yml - ejabberd.redis.yml - ejabberd.sqlite.yml @@ -12,6 +13,7 @@ host_config: pgsql.localhost: PGSQL_CONFIG sqlite.localhost: SQLITE_CONFIG mysql.localhost: MYSQL_CONFIG + mssql.localhost: MSSQL_CONFIG mnesia.localhost: MNESIA_CONFIG redis.localhost: REDIS_CONFIG ldap.localhost: LDAP_CONFIG @@ -26,6 +28,7 @@ hosts: - mnesia.localhost - redis.localhost - mysql.localhost + - mssql.localhost - pgsql.localhost - extauth.localhost - ldap.localhost diff --git a/test/ejabberd_SUITE_data/macros.yml b/test/ejabberd_SUITE_data/macros.yml index fd4e09f01..e4270d4c1 100644 --- a/test/ejabberd_SUITE_data/macros.yml +++ b/test/ejabberd_SUITE_data/macros.yml @@ -19,6 +19,11 @@ define_macro: MYSQL_PORT: @@mysql_port@@ MYSQL_PASS: "@@mysql_pass@@" MYSQL_DB: "@@mysql_db@@" + MSSQL_USER: "@@mssql_user@@" + MSSQL_SERVER: "@@mssql_server@@" + MSSQL_PORT: @@mssql_port@@ + MSSQL_PASS: "@@mssql_pass@@" + MSSQL_DB: "@@mssql_db@@" PGSQL_USER: "@@pgsql_user@@" PGSQL_SERVER: "@@pgsql_server@@" PGSQL_PORT: @@pgsql_port@@ diff --git a/test/suite.erl b/test/suite.erl index ca6123c60..e9a3bea9c 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -70,6 +70,11 @@ init_config(Config) -> {mysql_db, <<"ejabberd_test">>}, {mysql_user, <<"ejabberd_test">>}, {mysql_pass, <<"ejabberd_test">>}, + {mssql_server, <<"localhost">>}, + {mssql_port, 1433}, + {mssql_db, <<"ejabberd_test">>}, + {mssql_user, <<"ejabberd_test">>}, + {mssql_pass, <<"ejabberd_Test1">>}, {pgsql_server, <<"localhost">>}, {pgsql_port, 5432}, {pgsql_db, <<"ejabberd_test">>}, @@ -140,14 +145,26 @@ copy_backend_configs(DataDir, CWD, Backends) -> Backend = list_to_atom(SBackend), Macro = list_to_atom(string:to_upper(SBackend) ++ "_CONFIG"), Dst = filename:join([CWD, File]), - case lists:member(Backend, Backends) of - true -> - {ok, _} = file:copy(Src, Dst); - false -> - ok = file:write_file( - Dst, fast_yaml:encode( - [{define_macro, [{Macro, []}]}])) - end; + case Backend of + mssql -> + case lists:member(odbc, Backends) of + true -> + {ok, _} = file:copy(Src, Dst); + false -> + ok = file:write_file( + Dst, fast_yaml:encode( + [{define_macro, [{Macro, []}]}])) + end; + _ -> + case lists:member(Backend, Backends) of + true -> + {ok, _} = file:copy(Src, Dst); + false -> + ok = file:write_file( + Dst, fast_yaml:encode( + [{define_macro, [{Macro, []}]}])) + end + end; _ -> ok end diff --git a/test/suite.hrl b/test/suite.hrl index 194c48eb5..b3bab6c12 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -92,6 +92,7 @@ -define(MNESIA_VHOST, <<"mnesia.localhost">>). -define(REDIS_VHOST, <<"redis.localhost">>). -define(MYSQL_VHOST, <<"mysql.localhost">>). +-define(MSSQL_VHOST, <<"mssql.localhost">>). -define(PGSQL_VHOST, <<"pgsql.localhost">>). -define(SQLITE_VHOST, <<"sqlite.localhost">>). -define(LDAP_VHOST, <<"ldap.localhost">>). @@ -99,7 +100,7 @@ -define(S2S_VHOST, <<"s2s.localhost">>). -define(UPLOAD_VHOST, <<"upload.localhost">>). --define(BACKENDS, [mnesia, redis, mysql, pgsql, sqlite, ldap, extauth]). +-define(BACKENDS, [mnesia, redis, mysql, mssql, odbc, pgsql, sqlite, ldap, extauth]). insert(Val, N, Tuple) -> L = tuple_to_list(Tuple),