Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests to EmailPasswordClient #3472

Merged
merged 8 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Tests/Realm.Tests/Sync/SyncTestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static void RunBaasTestAsync(Func<Task> testFunc, int timeout = 30000)
Task.Delay(1000).Wait();
}

public static string GetVerifiedUsername() => $"realm_tests_do_autoverify-{Guid.NewGuid()}";
public static string GetVerifiedUsername() => $"realm_tests_do_autoverify-{Guid.NewGuid()}@g.it";

public static string GetUnconfirmedUsername() => $"realm_tests_do_not_confirm-{Guid.NewGuid()}@g.it";

Expand Down
80 changes: 79 additions & 1 deletion Tests/Realm.Tests/Sync/UserManagementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@

await DefaultApp.RemoveUserAsync(second);

// TODO: validate that the refresh token is invalidated.

Check warning on line 140 in Tests/Realm.Tests/Sync/UserManagementTests.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Tests/Realm.Tests/Sync/UserManagementTests.cs#L140

TODO entry doesn't have a link to Github issue or Jira ticket validate that the refresh token is invalidated.
Assert.That(second.State, Is.EqualTo(UserState.Removed));
Assert.That(second.AccessToken, Is.Empty);
Assert.That(second.RefreshToken, Is.Empty);
Expand Down Expand Up @@ -400,7 +400,7 @@
}

[Test]
public void User_RetryCustomConfirmationAsync_WorksInAllScenarios()
public void User_RetryCustomConfirmationAsync_RerunsConfirmation()
{
SyncTestHelpers.RunBaasTestAsync(async () =>
{
Expand Down Expand Up @@ -435,6 +435,84 @@
});
}

[Test]
public void User_ConfirmUserAsync_ConfirmsUser()
{
SyncTestHelpers.RunBaasTestAsync(async () =>
{
var unconfirmedMail = SyncTestHelpers.GetUnconfirmedUsername();
var credentials = Credentials.EmailPassword(unconfirmedMail, SyncTestHelpers.DefaultPassword);

// The first time the confirmation function is called we return "pending", so the user needs to be confirmed.
// At the same time we save the user email, token and tokenId in a collection.
await DefaultApp.EmailPasswordAuth.RegisterUserAsync(unconfirmedMail, SyncTestHelpers.DefaultPassword).Timeout(10_000, detail: "Failed to register user");

var ex = await TestHelpers.AssertThrows<AppException>(() => DefaultApp.LogInAsync(credentials));
Assert.That(ex.Message, Does.Contain("confirmation required"));

// This retrieves the token and tokenId we saved in the confirmation function
var functionUser = await GetUserAsync();
var result = await functionUser.Functions.CallAsync("confirmationInfo", unconfirmedMail);
var token = result["token"].AsString;
var tokenId = result["tokenId"].AsString;

await DefaultApp.EmailPasswordAuth.ConfirmUserAsync(token, tokenId);
var user = await DefaultApp.LogInAsync(credentials);
Assert.That(user.State, Is.EqualTo(UserState.LoggedIn));
});
}

[Test]
public void User_CallResetPasswordFunctionAsync_ResetsUserPassword()
{
SyncTestHelpers.RunBaasTestAsync(async () =>
{
var user = await GetUserAsync();
var email = user.Profile.Email!;

await user.LogOutAsync();
Assert.That(user.State, Is.EqualTo(UserState.Removed));

var newPassword = "realm_tests_do_reset-testPassword";
await DefaultApp.EmailPasswordAuth.CallResetPasswordFunctionAsync(email, newPassword);

user = await DefaultApp.LogInAsync(Credentials.EmailPassword(email, newPassword));
Assert.That(user.State, Is.EqualTo(UserState.LoggedIn));
});
}

[Test]
public void User_ResetPasswordAsync_ConfirmsResetPassword()
{
SyncTestHelpers.RunBaasTestAsync(async () =>
{
var user = await GetUserAsync();
var email = user.Profile.Email!;

await user.LogOutAsync();
Assert.That(user.State, Is.EqualTo(UserState.Removed));

// This returns "pending" the first time, so the password change is not valid yet. We save the token and tokenId
// passed to the reset function, to confirm the password change later.
var newPassword = "realm_tests_do_not_reset-testPassword";
await DefaultApp.EmailPasswordAuth.CallResetPasswordFunctionAsync(email, newPassword);

var ex = await TestHelpers.AssertThrows<AppException>(() => DefaultApp.LogInAsync(Credentials.EmailPassword(email, newPassword)));
Assert.That(ex.Message, Does.Contain("invalid username/password"));

// This retrieves the token and tokenId we saved in the password reset function.
var functionUser = await GetUserAsync();
var result = await functionUser.Functions.CallAsync("resetInfo", email);
var token = result["token"].AsString;
var tokenId = result["tokenId"].AsString;

await DefaultApp.EmailPasswordAuth.ResetPasswordAsync(newPassword, token, tokenId);

user = await DefaultApp.LogInAsync(Credentials.EmailPassword(email, newPassword));
Assert.That(user.State, Is.EqualTo(UserState.LoggedIn));
});
}

[Test]
public void User_JWT_LogsInAndReadsDataFromToken()
{
Expand Down
39 changes: 38 additions & 1 deletion Tools/DeployApps/BaasClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,32 @@ public class FunctionReturn
};";

private const string ResetFuncSource =
@"exports = ({ token, tokenId, username, password }) => {
@"exports = async function ({ token, tokenId, username, password, currentPasswordValid }) {
// process the reset token, tokenId, username and password
if (password.includes(""realm_tests_do_reset"")) {
return { status: 'success' };
}

if (password.includes(""realm_tests_do_not_reset"")) {
const mongodb = context.services.get('BackingDB');
let collection = mongodb.db('test_db').collection('not_reset');
let result = await collection.findOne({'email': username});

if(result === null)
{
let newVal = {
'email': username,
'token': token,
'tokenId': tokenId,
}

await collection.insertOne(newVal);
return { status: 'pending' };
}

return { status: 'success' };
}

// will not reset the password
return { status: 'fail' };
};";
Expand All @@ -148,6 +169,20 @@ public class FunctionReturn
}
};";

private const string ConfirmationInfoFuncSource =
@"exports = async function(username){
const mongodb = context.services.get('BackingDB');
let collection = mongodb.db('test_db').collection('not_confirmed');
return await collection.findOne({'email': username});
};";

private const string ResetPasswordInfoFuncSource =
@"exports = async function(username){
const mongodb = context.services.get('BackingDB');
let collection = mongodb.db('test_db').collection('not_reset');
return await collection.findOne({'email': username});
};";

private readonly HttpClient _client = new();

private readonly string? _clusterName;
Expand Down Expand Up @@ -302,6 +337,8 @@ private async Task<BaasApp> CreateDefaultApp(string name)
};");

await CreateFunction(app, "triggerClientResetOnSyncServer", TriggerClientResetOnSyncServerFuncSource, runAsSystem: true);
await CreateFunction(app, "confirmationInfo", ConfirmationInfoFuncSource, runAsSystem: true);
await CreateFunction(app, "resetInfo", ResetPasswordInfoFuncSource, runAsSystem: true);

await CreateFunction(app, "documentFunc", @"exports = function(first, second){
return {
Expand Down
Loading