-module(jchat_auth_SUITE). -compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). -include("../src/jchat.hrl"). %%==================================================================== %% CT Callbacks %%==================================================================== suite() -> [{timetrap, {seconds, 30}}]. init_per_suite(Config) -> % Start the application application:ensure_all_started(jchat), % Wait a bit for server to start timer:sleep(1000), Config. end_per_suite(_Config) -> application:stop(jchat), ok. init_per_testcase(_TestCase, Config) -> % Clean up any existing test data mnesia:clear_table(user), Config. end_per_testcase(_TestCase, _Config) -> ok. all() -> [test_user_registration, test_user_login, test_duplicate_email_registration, test_invalid_login, test_jwt_token_validation, test_jmap_api_authentication, test_password_hashing, test_user_creation_flow]. %%==================================================================== %% Test Cases %%==================================================================== test_user_registration(_Config) -> Email = <<"test@example.com">>, Password = <<"testpass123">>, DisplayName = <<"Test User">>, % Test user registration {ok, User} = jchat_auth:register_user(Email, Password, DisplayName), % Verify user fields ?assertEqual(Email, User#user.email), ?assertEqual(DisplayName, User#user.display_name), ?assert(is_binary(User#user.id)), ?assert(is_binary(User#user.password_hash)), ?assertNotEqual(Password, User#user.password_hash), ?assertEqual(true, User#user.is_active), ?assertEqual(<<"local">>, User#user.auth_provider). test_user_login(_Config) -> Email = <<"test@example.com">>, Password = <<"testpass123">>, DisplayName = <<"Test User">>, % Register user first {ok, _User} = jchat_auth:register_user(Email, Password, DisplayName), % Test login {ok, {AuthUser, Token}} = jchat_auth:authenticate_user(Email, Password), % Verify user and token ?assertEqual(Email, AuthUser#user.email), ?assert(is_binary(Token)), ?assert(byte_size(Token) > 0). test_duplicate_email_registration(_Config) -> Email = <<"test@example.com">>, Password = <<"testpass123">>, DisplayName = <<"Test User">>, % Register user first time {ok, _User} = jchat_auth:register_user(Email, Password, DisplayName), % Try to register same email again Result = jchat_auth:register_user(Email, Password, DisplayName), ?assertMatch({error, _}, Result). test_invalid_login(_Config) -> Email = <<"test@example.com">>, Password = <<"testpass123">>, WrongPassword = <<"wrongpass">>, DisplayName = <<"Test User">>, % Register user {ok, _User} = jchat_auth:register_user(Email, Password, DisplayName), % Try login with wrong password Result = jchat_auth:authenticate_user(Email, WrongPassword), ?assertMatch({error, _}, Result), % Try login with non-existent email Result2 = jchat_auth:authenticate_user(<<"nonexistent@example.com">>, Password), ?assertMatch({error, _}, Result2). test_jwt_token_validation(_Config) -> Email = <<"test@example.com">>, Password = <<"testpass123">>, DisplayName = <<"Test User">>, % Register and login {ok, _User} = jchat_auth:register_user(Email, Password, DisplayName), {ok, {AuthUser, Token}} = jchat_auth:authenticate_user(Email, Password), % Validate token {ok, ValidatedUser} = jchat_auth:validate_token(Token), ?assertEqual(AuthUser#user.id, ValidatedUser#user.id), ?assertEqual(AuthUser#user.email, ValidatedUser#user.email), % Test invalid token InvalidToken = <<"invalid.token.here">>, Result = jchat_auth:validate_token(InvalidToken), ?assertMatch({error, _}, Result). test_jmap_api_authentication(_Config) -> Email = <<"test@example.com">>, Password = <<"testpass123">>, DisplayName = <<"Test User">>, % Register and login {ok, _User} = jchat_auth:register_user(Email, Password, DisplayName), {ok, {_AuthUser, Token}} = jchat_auth:authenticate_user(Email, Password), % Create mock request with auth header AuthHeader = <<"Bearer ", Token/binary>>, % Test authentication context creation {ok, AuthContext} = jchat_auth:create_auth_context(AuthHeader), ?assertMatch(#{user := _, account_id := _}, AuthContext), User = maps:get(user, AuthContext), ?assertEqual(Email, User#user.email). test_password_hashing(_Config) -> Password1 = <<"password123">>, Password2 = <<"password123">>, Password3 = <<"differentpass">>, % Hash the same password twice Hash1 = jchat_auth:hash_password(Password1), Hash2 = jchat_auth:hash_password(Password2), % Hashes should be different (salt makes them unique) ?assertNotEqual(Hash1, Hash2), % But both should verify correctly ?assert(jchat_auth:verify_password(Password1, Hash1)), ?assert(jchat_auth:verify_password(Password2, Hash2)), % Wrong password should not verify ?assertNot(jchat_auth:verify_password(Password3, Hash1)). test_user_creation_flow(_Config) -> % Test the full user creation flow including database storage Email = <<"flow.test@example.com">>, Password = <<"flowtest123">>, DisplayName = <<"Flow Test User">>, % Register user (this should create in database) {ok, User} = jchat_auth:register_user(Email, Password, DisplayName), UserId = User#user.id, % Verify user exists in database {ok, DbUser} = jchat_db:get_user_by_id(UserId), ?assertEqual(Email, DbUser#user.email), ?assertEqual(DisplayName, DbUser#user.display_name), % Verify user can be found by email {ok, EmailUser} = jchat_db:get_user_by_email(Email), ?assertEqual(UserId, EmailUser#user.id), % Test login retrieves the same user {ok, {LoginUser, _Token}} = jchat_auth:authenticate_user(Email, Password), ?assertEqual(UserId, LoginUser#user.id).