From 5134184935154e0d3719aa88d8f12270bf09b563 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Wed, 6 Sep 2023 13:30:31 +0530 Subject: [PATCH] fix: pr comments --- .../multitenancy/Multitenancy.java | 44 +- ...ryUserWithEmailAlreadyExistsException.java | 23 + ...WithPhoneNumberAlreadyExistsException.java | 23 + ...hThirdPartyInfoAlreadyExistsException.java | 23 + .../AssociateUserToTenantAPI.java | 10 + .../test/accountlinking/MultitenantTest.java | 643 +++++++++++------- 6 files changed, 515 insertions(+), 251 deletions(-) create mode 100644 src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java create mode 100644 src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java create mode 100644 src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java diff --git a/src/main/java/io/supertokens/multitenancy/Multitenancy.java b/src/main/java/io/supertokens/multitenancy/Multitenancy.java index 88d2b5706..1aaa2a61e 100644 --- a/src/main/java/io/supertokens/multitenancy/Multitenancy.java +++ b/src/main/java/io/supertokens/multitenancy/Multitenancy.java @@ -384,7 +384,9 @@ public static boolean addUserIdToTenant(Main main, TenantIdentifierWithStorage t String userId) throws TenantOrAppNotFoundException, UnknownUserIdException, StorageQueryException, FeatureNotEnabledException, DuplicateEmailException, DuplicatePhoneNumberException, - DuplicateThirdPartyUserException { + DuplicateThirdPartyUserException, AnotherPrimaryUserWithPhoneNumberAlreadyExistsException, + AnotherPrimaryUserWithEmailAlreadyExistsException, + AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException { if (Arrays.stream(FeatureFlag.getInstance(main, new AppIdentifier(null, null)).getEnabledFeatures()) .noneMatch(ee_features -> ee_features == EE_FEATURES.MULTI_TENANCY)) { throw new FeatureNotEnabledException(EE_FEATURES.MULTI_TENANCY); @@ -418,7 +420,16 @@ public static boolean addUserIdToTenant(Main main, TenantIdentifierWithStorage t AuthRecipeUserInfo[] users = storage.listPrimaryUsersByEmail_Transaction(tenantIdentifierWithStorage.toAppIdentifier(), con, email); for (AuthRecipeUserInfo user : users) { if (user.tenantIds.contains(tenantId) && !user.getSupertokensUserId().equals(userId)) { - throw new StorageTransactionLogicException(new DuplicateEmailException()); + for (LoginMethod lm1 : user.loginMethods) { + if (lm1.tenantIds.contains(tenantId)) { + for (LoginMethod lm2 : userToAssociate.loginMethods) { + if (lm1.recipeId.equals(lm2.recipeId) && email.equals(lm1.email) && lm1.email.equals(lm2.email)) { + throw new StorageTransactionLogicException(new DuplicateEmailException()); + } + } + } + } + throw new StorageTransactionLogicException(new AnotherPrimaryUserWithEmailAlreadyExistsException(user.getSupertokensUserId())); } } } @@ -427,7 +438,16 @@ public static boolean addUserIdToTenant(Main main, TenantIdentifierWithStorage t AuthRecipeUserInfo[] users = storage.listPrimaryUsersByPhoneNumber_Transaction(tenantIdentifierWithStorage.toAppIdentifier(), con, phoneNumber); for (AuthRecipeUserInfo user : users) { if (user.tenantIds.contains(tenantId) && !user.getSupertokensUserId().equals(userId)) { - throw new StorageTransactionLogicException(new DuplicatePhoneNumberException()); + for (LoginMethod lm1 : user.loginMethods) { + if (lm1.tenantIds.contains(tenantId)) { + for (LoginMethod lm2 : userToAssociate.loginMethods) { + if (lm1.recipeId.equals(lm2.recipeId) && phoneNumber.equals(lm1.phoneNumber) && lm1.phoneNumber.equals(lm2.phoneNumber)) { + throw new StorageTransactionLogicException(new DuplicatePhoneNumberException()); + } + } + } + } + throw new StorageTransactionLogicException(new AnotherPrimaryUserWithPhoneNumberAlreadyExistsException(user.getSupertokensUserId())); } } } @@ -436,7 +456,17 @@ public static boolean addUserIdToTenant(Main main, TenantIdentifierWithStorage t AuthRecipeUserInfo[] users = storage.listPrimaryUsersByThirdPartyInfo_Transaction(tenantIdentifierWithStorage.toAppIdentifier(), con, tp.id, tp.userId); for (AuthRecipeUserInfo user : users) { if (user.tenantIds.contains(tenantId) && !user.getSupertokensUserId().equals(userId)) { - throw new StorageTransactionLogicException(new DuplicateThirdPartyUserException()); + for (LoginMethod lm1 : user.loginMethods) { + if (lm1.tenantIds.contains(tenantId)) { + for (LoginMethod lm2 : userToAssociate.loginMethods) { + if (lm1.recipeId.equals(lm2.recipeId) && tp.equals(lm1.thirdParty) && lm1.thirdParty.equals(lm2.thirdParty)) { + throw new StorageTransactionLogicException(new DuplicateThirdPartyUserException()); + } + } + } + } + + throw new StorageTransactionLogicException(new AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException(user.getSupertokensUserId())); } } } @@ -465,6 +495,12 @@ public static boolean addUserIdToTenant(Main main, TenantIdentifierWithStorage t throw (TenantOrAppNotFoundException) e.actualException; } else if (e.actualException instanceof UnknownUserIdException) { throw (UnknownUserIdException) e.actualException; + } else if (e.actualException instanceof AnotherPrimaryUserWithPhoneNumberAlreadyExistsException) { + throw (AnotherPrimaryUserWithPhoneNumberAlreadyExistsException) e.actualException; + } else if (e.actualException instanceof AnotherPrimaryUserWithEmailAlreadyExistsException) { + throw (AnotherPrimaryUserWithEmailAlreadyExistsException) e.actualException; + } else if (e.actualException instanceof AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException) { + throw (AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException) e.actualException; } throw new StorageQueryException(e.actualException); } diff --git a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java new file mode 100644 index 000000000..c95bfdcc3 --- /dev/null +++ b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithEmailAlreadyExistsException.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.multitenancy.exception; + +public class AnotherPrimaryUserWithEmailAlreadyExistsException extends Exception { + public AnotherPrimaryUserWithEmailAlreadyExistsException(String primaryUserId) { + super("Another primary user with email already exists: " + primaryUserId); + } +} diff --git a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java new file mode 100644 index 000000000..e012f9349 --- /dev/null +++ b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithPhoneNumberAlreadyExistsException.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.multitenancy.exception; + +public class AnotherPrimaryUserWithPhoneNumberAlreadyExistsException extends Exception { + public AnotherPrimaryUserWithPhoneNumberAlreadyExistsException(String primaryUserId) { + super("Another primary user with phone number already exists: " + primaryUserId); + } +} diff --git a/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java new file mode 100644 index 000000000..d5f413cf5 --- /dev/null +++ b/src/main/java/io/supertokens/multitenancy/exception/AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.multitenancy.exception; + +public class AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException extends Exception { + public AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException(String primaryUserId) { + super("Another primary user with third party info already exists: " + primaryUserId); + } +} diff --git a/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java b/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java index d53c2e7e8..3eb502dc5 100644 --- a/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java +++ b/src/main/java/io/supertokens/webserver/api/multitenancy/AssociateUserToTenantAPI.java @@ -21,6 +21,9 @@ import io.supertokens.Main; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; import io.supertokens.multitenancy.Multitenancy; +import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithEmailAlreadyExistsException; +import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithPhoneNumberAlreadyExistsException; +import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; import io.supertokens.pluginInterface.RECIPE_ID; import io.supertokens.pluginInterface.emailpassword.exceptions.DuplicateEmailException; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; @@ -99,6 +102,13 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I JsonObject result = new JsonObject(); result.addProperty("status", "THIRD_PARTY_USER_ALREADY_EXISTS_ERROR"); super.sendJsonResponse(200, result, resp); + + } catch (AnotherPrimaryUserWithEmailAlreadyExistsException | AnotherPrimaryUserWithPhoneNumberAlreadyExistsException | + AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException e) { + JsonObject result = new JsonObject(); + result.addProperty("status", "ASSOCIATION_NOT_ALLOWED_ERROR"); + result.addProperty("reason", e.getMessage()); + super.sendJsonResponse(200, result, resp); } } } diff --git a/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java b/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java index f9cdc8e12..09e104436 100644 --- a/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java +++ b/src/test/java/io/supertokens/test/accountlinking/MultitenantTest.java @@ -22,11 +22,14 @@ import io.supertokens.authRecipe.AuthRecipe; import io.supertokens.authRecipe.exception.AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException; import io.supertokens.emailpassword.EmailPassword; +import io.supertokens.emailpassword.exceptions.EmailChangeNotAllowedException; import io.supertokens.emailpassword.exceptions.WrongCredentialsException; import io.supertokens.featureflag.EE_FEATURES; import io.supertokens.featureflag.FeatureFlagTestContent; import io.supertokens.featureflag.exceptions.FeatureNotEnabledException; import io.supertokens.multitenancy.Multitenancy; +import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithEmailAlreadyExistsException; +import io.supertokens.multitenancy.exception.AnotherPrimaryUserWithThirdPartyInfoAlreadyExistsException; import io.supertokens.multitenancy.exception.BadPermissionException; import io.supertokens.multitenancy.exception.CannotModifyBaseConfigException; import io.supertokens.passwordless.Passwordless; @@ -48,10 +51,11 @@ import org.junit.rules.TestRule; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.function.Function; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class MultitenantTest { @Rule @@ -67,7 +71,7 @@ public void beforeEach() { Utils.reset(); } - TenantIdentifier t1, t2, t3; + TenantIdentifier t1, t2, t3, t4; private void createTenants(Main main) throws StorageQueryException, TenantOrAppNotFoundException, InvalidProviderConfigException, @@ -136,292 +140,437 @@ private void createTenants(Main main) ); } + { // tenant 4 + JsonObject config = new JsonObject(); + TenantIdentifier tenantIdentifier = new TenantIdentifier(null, "a1", "t3"); + + StorageLayer.getStorage(new TenantIdentifier(null, null, null), main) + .modifyConfigToAddANewUserPoolForTesting(config, 1); + + Multitenancy.addNewOrUpdateAppOrTenant( + main, + new TenantIdentifier(null, "a1", null), + new TenantConfig( + tenantIdentifier, + new EmailPasswordConfig(true), + new ThirdPartyConfig(true, null), + new PasswordlessConfig(true), + config + ) + ); + } + } + + @Test + public void testVariousCases() throws Exception { t1 = new TenantIdentifier(null, "a1", null); t2 = new TenantIdentifier(null, "a1", "t1"); t3 = new TenantIdentifier(null, "a1", "t2"); + t4 = new TenantIdentifier(null, "a1", "t3"); + + TestCase[] testCases = new TestCase[]{ + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t1, 2).expect(new DuplicateEmailException()), + new AssociateUserToTenant(t2, 2), // Allowed + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new MakePrimaryUser(t3, 2), + new AssociateUserToTenant(t2, 2).expect(new AnotherPrimaryUserWithEmailAlreadyExistsException("")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t2, 2), + new MakePrimaryUser(t3, 2).expect(new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreatePlessUserWithEmail(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t1, 2).expect(new DuplicateEmailException()), + new AssociateUserToTenant(t2, 2), // Allowed + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreatePlessUserWithEmail(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new MakePrimaryUser(t3, 2), + new AssociateUserToTenant(t2, 2).expect(new AnotherPrimaryUserWithEmailAlreadyExistsException("")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreatePlessUserWithEmail(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t2, 2), + new MakePrimaryUser(t3, 2).expect(new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), + }), + + new TestCase(new TestCaseStep[]{ + new CreatePlessUserWithEmail(t1, "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t1, 2), + new AssociateUserToTenant(t2, 2), // Allowed + }), + + new TestCase(new TestCaseStep[]{ + new CreatePlessUserWithEmail(t1, "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new MakePrimaryUser(t3, 2), + new AssociateUserToTenant(t2, 2).expect(new AnotherPrimaryUserWithEmailAlreadyExistsException("")), + }), + + new TestCase(new TestCaseStep[]{ + new CreatePlessUserWithEmail(t1, "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t2, 2), + new MakePrimaryUser(t3, 2).expect(new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), + }), + + new TestCase(new TestCaseStep[]{ + new CreatePlessUserWithEmail(t1, "test1@example.com"), + new CreatePlessUserWithEmail(t2, "test2@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 2), + new UpdatePlessUserEmail(t1, 0, "test2@example.com"), + }), + + new TestCase(new TestCaseStep[]{ + new CreatePlessUserWithEmail(t1, "test1@example.com"), + new CreatePlessUserWithEmail(t1, "test3@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 2), + new MakePrimaryUser(t2, 1), + new UpdatePlessUserEmail(t1, 0, "test3@example.com").expect(new EmailChangeNotAllowedException()), + }), + + new TestCase(new TestCaseStep[]{ + new CreatePlessUserWithEmail(t1, "test1@example.com"), + new CreatePlessUserWithEmail(t1, "test3@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 2), + new MakePrimaryUser(t2, 1), + new UpdatePlessUserEmail(t1, 1, "test1@example.com").expect(new EmailChangeNotAllowedException()), + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreateThirdPartyUser(t2, "google", "googleid", "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t1, 2).expect(new DuplicateEmailException()), + new AssociateUserToTenant(t2, 2), // Allowed + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreateThirdPartyUser(t2, "google", "googleid", "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new MakePrimaryUser(t3, 2), + new AssociateUserToTenant(t2, 2).expect(new AnotherPrimaryUserWithEmailAlreadyExistsException("")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateEmailPasswordUser(t1, "test1@example.com"), + new CreateThirdPartyUser(t2, "google", "googleid", "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t2, 2), + new MakePrimaryUser(t3, 2).expect(new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t1, 2), + new AssociateUserToTenant(t2, 2), // Allowed + }), + + new TestCase(new TestCaseStep[]{ + new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new MakePrimaryUser(t3, 2), + new AssociateUserToTenant(t2, 2).expect(new AnotherPrimaryUserWithEmailAlreadyExistsException("")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateThirdPartyUser(t1, "google", "googleid", "test1@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 1), + new CreateEmailPasswordUser(t3, "test1@example.com"), + new AssociateUserToTenant(t2, 2), + new MakePrimaryUser(t3, 2).expect(new AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException("", "")), + }), + + new TestCase(new TestCaseStep[]{ + new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), + new CreateThirdPartyUser(t2, "google", "googleid2", "test2@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 2), + new CreateThirdPartyUser(t1, "google", "googleid1", "test2@example.com"), + }), + + new TestCase(new TestCaseStep[]{ + new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), + new CreateThirdPartyUser(t1, "google", "googleid3", "test3@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 2), + new MakePrimaryUser(t2, 1), + new CreateThirdPartyUser(t1, "google", "googleid1", "test3@example.com").expect(new EmailChangeNotAllowedException()), + }), + + new TestCase(new TestCaseStep[]{ + new CreateThirdPartyUser(t1, "google", "googleid1", "test1@example.com"), + new CreateThirdPartyUser(t1, "google", "googleid3", "test3@example.com"), + new CreateEmailPasswordUser(t2, "test2@example.com"), + new MakePrimaryUser(t1, 0), + new LinkAccounts(t1, 0, 2), + new MakePrimaryUser(t2, 1), + new CreateThirdPartyUser(t1, "google", "googleid3", "test1@example.com").expect(new EmailChangeNotAllowedException()), + }), + }; + + int i = 0; + for (TestCase testCase : testCases) { + String[] args = {"../"}; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + FeatureFlagTestContent.getInstance(process.getProcess()) + .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ + EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); + process.startProcess(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + createTenants(process.getProcess()); + + System.out.println("Executing test case : " + i); + testCase.doTest(process.getProcess()); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + i++; + } } - @Test - public void testWithEmailPasswordUsers1() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password"); - AuthRecipeUserInfo user2 = EmailPassword.signUp(t2WithStorage, process.getProcess(), "test2@example.com", "password"); - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - try { - // Credentials does not exist in t2 - EmailPassword.signIn(t2WithStorage, process.getProcess(), "test1@example.com", "password"); - fail(); - } catch (WrongCredentialsException e) { - // ignore + private static class TestCase { + TestCaseStep[] steps; + public static List users; + + public static void resetUsers() { + users = new ArrayList<>(); } - Multitenancy.addUserIdToTenant(process.getProcess(), t2WithStorage, user1.getSupertokensUserId()); + public static void addUser(AuthRecipeUserInfo user) { + users.add(user); + } - // Sign in should now pass - EmailPassword.signIn(t2WithStorage, process.getProcess(), "test1@example.com", "password"); + public TestCase(TestCaseStep[] steps) { + this.steps = steps; + } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); - } + public void doTest(Main main) throws Exception { + TestCase.resetUsers(); - @Test - public void testWithEmailPasswordUsers2() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password"); - AuthRecipeUserInfo user2 = EmailPassword.signUp(t2WithStorage, process.getProcess(), "test2@example.com", "password"); - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - try { - // Credentials does not exist in t2 - EmailPassword.signIn(t2WithStorage, process.getProcess(), "test1@example.com", "password"); - fail(); - } catch (WrongCredentialsException e) { - // ignore + for (TestCaseStep step : steps) { + step.doStep(main); + } } + } - // same email is allowed to sign up - AuthRecipeUserInfo user3 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test2@example.com", "password2"); + private static class TestCaseStep { + Exception e; - // Sign in should pass - EmailPassword.signIn(t1WithStorage, process.getProcess(), "test2@example.com", "password2"); + public TestCaseStep expect(Exception e) { + this.e = e; + return this; + } - try { - // user 3 cannot become a primary user - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user3.getSupertokensUserId()); - fail(); - } catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) { - // Ignore + public void doStep(Main main) throws Exception { + if (e == null) { + this.execute(main); + } else { + try { + this.execute(main); + fail(); + } catch (Exception e) { + assertEquals(this.e.getClass(), e.getClass()); + } + } } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + public void execute(Main main) throws Exception { + } } - @Test - public void testWithEmailPasswordUsersAndPasswordlessUser1() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password"); - Passwordless.CreateCodeResponse user2Code = Passwordless.createCode(t2WithStorage, process.getProcess(), - "test2@example.com", null, null, null); - AuthRecipeUserInfo user2 = Passwordless.consumeCode(t2WithStorage, process.getProcess(), user2Code.deviceId, user2Code.deviceIdHash, user2Code.userInputCode, null).user; - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - try { - // Credentials does not exist in t2 - EmailPassword.signIn(t2WithStorage, process.getProcess(), "test1@example.com", "password"); - fail(); - } catch (WrongCredentialsException e) { - // ignore + private static class CreateEmailPasswordUser extends TestCaseStep { + private final TenantIdentifier tenantIdentifier; + private final String email; + + public CreateEmailPasswordUser(TenantIdentifier tenantIdentifier, String email) { + this.tenantIdentifier = tenantIdentifier; + this.email = email; } - // same email is allowed to sign up - AuthRecipeUserInfo user3 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test2@example.com", "password2"); + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + AuthRecipeUserInfo user = EmailPassword.signUp(tenantIdentifierWithStorage, main, email, "password"); + TestCase.addUser(user); + } + } - // Sign in should pass - EmailPassword.signIn(t1WithStorage, process.getProcess(), "test2@example.com", "password2"); + private static class CreatePlessUserWithEmail extends TestCaseStep { + private final TenantIdentifier tenantIdentifier; + private final String email; - try { - // user 3 cannot become a primary user - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user3.getSupertokensUserId()); - fail(); - } catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) { - // Ignore + public CreatePlessUserWithEmail(TenantIdentifier tenantIdentifier, String email) { + this.tenantIdentifier = tenantIdentifier; + this.email = email; } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + Passwordless.CreateCodeResponse code = Passwordless.createCode(tenantIdentifierWithStorage, main, + email, null, null, null); + AuthRecipeUserInfo user = Passwordless.consumeCode(tenantIdentifierWithStorage, main, code.deviceId, code.deviceIdHash, code.userInputCode, null).user; + TestCase.addUser(user); + } } - @Test - public void testWithEmailPasswordUsersAndPasswordlessUser2() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password"); - Passwordless.CreateCodeResponse user2Code = Passwordless.createCode(t2WithStorage, process.getProcess(), - "test2@example.com", null, null, null); - AuthRecipeUserInfo user2 = Passwordless.consumeCode(t2WithStorage, process.getProcess(), user2Code.deviceId, user2Code.deviceIdHash, user2Code.userInputCode, null).user; - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - // same email is allowed to sign in up - Passwordless.CreateCodeResponse user3code = Passwordless.createCode(t1WithStorage, process.getProcess(), - "test2@example.com", null, null, null); - - AuthRecipeUserInfo user3 = Passwordless.consumeCode(t1WithStorage, process.getProcess(), user3code.deviceId, user3code.deviceIdHash, user3code.userInputCode, null).user; - - try { - // user 3 cannot become a primary user - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user3.getSupertokensUserId()); - fail(); - } catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) { - // Ignore + private static class CreateThirdPartyUser extends TestCaseStep { + TenantIdentifier tenantIdentifier; + String thirdPartyId; + String thirdPartyUserId; + String email; + + public CreateThirdPartyUser(TenantIdentifier tenantIdentifier, String thirdPartyId, String thirdPartyUserId, String email) { + this.tenantIdentifier = tenantIdentifier; + this.thirdPartyId = thirdPartyId; + this.thirdPartyUserId = thirdPartyUserId; + this.email = email; } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + AuthRecipeUserInfo user = ThirdParty.signInUp(tenantIdentifierWithStorage, main, thirdPartyId, thirdPartyUserId, email).user; + TestCase.addUser(user); + } } - @Test - public void testWithEmailPasswordUserAndThirdPartyUser() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password"); - AuthRecipeUserInfo user2 = ThirdParty.signInUp(t2WithStorage, process.getProcess(), "google", "google-user", "test2@example.com").user; - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - try { - // Credentials does not exist in t2 - EmailPassword.signIn(t2WithStorage, process.getProcess(), "test1@example.com", "password"); - fail(); - } catch (WrongCredentialsException e) { - // ignore + private static class MakePrimaryUser extends TestCaseStep { + TenantIdentifier tenantIdentifier; + int userIndex; + + public MakePrimaryUser(TenantIdentifier tenantIdentifier, int userIndex) { + this.tenantIdentifier = tenantIdentifier; + this.userIndex = userIndex; + } + + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + AuthRecipe.createPrimaryUser(main, tenantIdentifierWithStorage.toAppIdentifierWithStorage(), TestCase.users.get(userIndex).getSupertokensUserId()); } + } - // same email is allowed to sign up - AuthRecipeUserInfo user3 = ThirdParty.signInUp(t1WithStorage, process.getProcess(), "google", "google-user", "test2@example.com").user; + private static class LinkAccounts extends TestCaseStep { + TenantIdentifier tenantIdentifier; + int primaryUserIndex; + int recipeUserIndex; - try { - // user 3 cannot become a primary user - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user3.getSupertokensUserId()); - fail(); - } catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) { - // Ignore + public LinkAccounts(TenantIdentifier tenantIdentifier, int primaryUserIndex, int recipeUserIndex) { + this.tenantIdentifier = tenantIdentifier; + this.primaryUserIndex = primaryUserIndex; + this.recipeUserIndex = recipeUserIndex; } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + AuthRecipe.linkAccounts(main, tenantIdentifierWithStorage.toAppIdentifierWithStorage(), TestCase.users.get(recipeUserIndex).getSupertokensUserId(), TestCase.users.get(primaryUserIndex).getSupertokensUserId()); + } } - @Test - public void testTenantAssociationWithEPUsers1() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - TenantIdentifierWithStorage t3WithStorage = t3.withStorage(StorageLayer.getStorage(t3, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password1"); - AuthRecipeUserInfo user2 = EmailPassword.signUp(t2WithStorage, process.getProcess(), "test2@example.com", "password2"); - AuthRecipeUserInfo user3 = EmailPassword.signUp(t3WithStorage, process.getProcess(), "test1@example.com", "password3"); - - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - Multitenancy.addUserIdToTenant(process.getProcess(), t2WithStorage, user3.getSupertokensUserId()); - try { - AuthRecipe.createPrimaryUser(process.getProcess(), t2WithStorage.toAppIdentifierWithStorage(), user3.getSupertokensUserId()); - fail(); - } catch (AccountInfoAlreadyAssociatedWithAnotherPrimaryUserIdException e) { - // ignore + private static class AssociateUserToTenant extends TestCaseStep { + TenantIdentifier tenantIdentifier; + int userIndex; + + public AssociateUserToTenant(TenantIdentifier tenantIdentifier, int userIndex) { + this.tenantIdentifier = tenantIdentifier; + this.userIndex = userIndex; } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + Multitenancy.addUserIdToTenant(main, tenantIdentifierWithStorage, TestCase.users.get(userIndex).getSupertokensUserId()); + } } - @Test - public void testTenantAssociationWithEPUsers2() throws Exception { - String[] args = {"../"}; - TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); - FeatureFlagTestContent.getInstance(process.getProcess()) - .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ - EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); - process.startProcess(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); - - createTenants(process.getProcess()); - - TenantIdentifierWithStorage t1WithStorage = t1.withStorage(StorageLayer.getStorage(t1, process.getProcess())); - TenantIdentifierWithStorage t2WithStorage = t2.withStorage(StorageLayer.getStorage(t2, process.getProcess())); - TenantIdentifierWithStorage t3WithStorage = t3.withStorage(StorageLayer.getStorage(t3, process.getProcess())); - - AuthRecipeUserInfo user1 = EmailPassword.signUp(t1WithStorage, process.getProcess(), "test1@example.com", "password1"); - AuthRecipeUserInfo user2 = EmailPassword.signUp(t2WithStorage, process.getProcess(), "test2@example.com", "password2"); - AuthRecipeUserInfo user3 = EmailPassword.signUp(t3WithStorage, process.getProcess(), "test1@example.com", "password3"); - - AuthRecipe.createPrimaryUser(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user1.getSupertokensUserId()); - AuthRecipe.linkAccounts(process.getProcess(), t1WithStorage.toAppIdentifierWithStorage(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); - - AuthRecipe.createPrimaryUser(process.getProcess(), t2WithStorage.toAppIdentifierWithStorage(), user3.getSupertokensUserId()); - try { - Multitenancy.addUserIdToTenant(process.getProcess(), t2WithStorage, user3.getSupertokensUserId()); - fail(); - } catch (DuplicateEmailException e) { - // ignore + private static class UpdatePlessUserEmail extends TestCaseStep { + TenantIdentifier tenantIdentifier; + int userIndex; + String email; + + public UpdatePlessUserEmail(TenantIdentifier tenantIdentifier, int userIndex, String email) { + this.tenantIdentifier = tenantIdentifier; + this.userIndex = userIndex; + this.email = email; } - process.kill(); - assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + @Override + public void execute(Main main) throws Exception { + TenantIdentifierWithStorage tenantIdentifierWithStorage = tenantIdentifier.withStorage(StorageLayer.getStorage(tenantIdentifier, main)); + Passwordless.updateUser(tenantIdentifierWithStorage.toAppIdentifierWithStorage(), TestCase.users.get(userIndex).getSupertokensUserId(), new Passwordless.FieldUpdate(email), null); + } } }