From 4661e9c4f6a4e91723a21ca41c0f29dc7b3dca71 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 00:50:11 +0100 Subject: [PATCH 01/10] create PasswordEncoder for AccountServiceTest mocked --- .../hs/fulda/de/ci/exam/project/Account.java | 22 ++++++++++++ .../de/ci/exam/project/AccountRepository.java | 5 +++ .../de/ci/exam/project/AccountService.java | 24 +++++++++++++ .../ci/exam/project/AccountServiceTest.java | 35 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 src/main/java/hs/fulda/de/ci/exam/project/AccountService.java create mode 100644 src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java diff --git a/src/main/java/hs/fulda/de/ci/exam/project/Account.java b/src/main/java/hs/fulda/de/ci/exam/project/Account.java index b5bbaa8..7097e7e 100644 --- a/src/main/java/hs/fulda/de/ci/exam/project/Account.java +++ b/src/main/java/hs/fulda/de/ci/exam/project/Account.java @@ -33,6 +33,15 @@ public class Account { this.status = status; } + public boolean isEnabled() { + if(status == AccountStatus.ACTIVE) return true; + return false; + } + + public String getPasswordHash() { + return new PasswordEncoder().encode(password); + } + public enum AccountStatus { ACTIVE, CLOSED, @@ -67,4 +76,17 @@ public class Account { } } +class PasswordEncoder{ + String encode(String password){ + int p = 31; + int m = (int) Math.pow(10, 9) + 9; + int hash_value = 0; + int p_pow = 1; + for (char c : password.toCharArray()) { + hash_value = (hash_value + (c - 'a' + 1) * p_pow) % m; + p_pow = (p_pow * p) % m; + } + return Integer.toString(hash_value); + } +} diff --git a/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java b/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java index db9d3e8..90a96db 100644 --- a/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java +++ b/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java @@ -14,6 +14,11 @@ public class AccountRepository { } return false; } + Account findById(String id){ + Account account = accountList.get(id); + return account; + } + private String generateKey(Account account) { return String.format("%s", account.getId()); } diff --git a/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java b/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java new file mode 100644 index 0000000..789ecba --- /dev/null +++ b/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java @@ -0,0 +1,24 @@ +package hs.fulda.de.ci.exam.project; + +public class AccountService { + private final AccountRepository accountRepository; + private final PasswordEncoder passwordEncoder; + + public AccountService(AccountRepository accountRepository, PasswordEncoder passwordEncoder) { + this.accountRepository = accountRepository; + this.passwordEncoder = passwordEncoder; + } + public boolean isValidAccount(String id, String password){ + Account account = accountRepository.findById(id); + return isEnabledAccount(account) && isValidPassword(account, password); + } + + private boolean isEnabledAccount(Account account) { + return account!= null && account.isEnabled(); + } + + private boolean isValidPassword(Account account, String password) { + String encodedPassword = passwordEncoder.encode(password); + return encodedPassword.equals(account.getPasswordHash()); + } +} diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java new file mode 100644 index 0000000..c9f1bdc --- /dev/null +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -0,0 +1,35 @@ +package hs.fulda.de.ci.exam.project; + +import org.junit.Before; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AccountServiceTest { + private static final String PASSWORD = "password"; + + private static final Account ENABLED_USER = + new Account("user id", "hash", Account.AccountStatus.ACTIVE); + + private static final Account DISABLED_USER = + new Account("disabled user id", "disabled user password hash", Account.AccountStatus.CLOSED); + + private AccountRepository accountRepository; + private PasswordEncoder passwordEncoder; + private AccountService accountService; + + @Before + public void setup() { + passwordEncoder = createPasswordEncoder(); + accountService = new AccountService(accountRepository, passwordEncoder); + } + + private PasswordEncoder createPasswordEncoder() { + PasswordEncoder mock = mock(PasswordEncoder.class); + when(mock.encode(anyString())).thenReturn("any password hash"); + when(mock.encode(PASSWORD)).thenReturn(ENABLED_USER.getPasswordHash()); + return mock; + } + +} From 2d27fc1d5e3825644144c81da86ea1788db6d9d2 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 00:52:01 +0100 Subject: [PATCH 02/10] create Account Repository for AccountServiceTest mocked --- .../hs/fulda/de/ci/exam/project/AccountServiceTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index c9f1bdc..f5ab438 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -21,10 +21,18 @@ public class AccountServiceTest { @Before public void setup() { + accountRepository = createAccountRepository(); passwordEncoder = createPasswordEncoder(); accountService = new AccountService(accountRepository, passwordEncoder); } + private AccountRepository createAccountRepository() { + AccountRepository mock = mock(AccountRepository.class); + when(mock.findById(ENABLED_USER.getId())).thenReturn(ENABLED_USER); + when(mock.findById(DISABLED_USER.getId())).thenReturn(DISABLED_USER); + return mock; + } + private PasswordEncoder createPasswordEncoder() { PasswordEncoder mock = mock(PasswordEncoder.class); when(mock.encode(anyString())).thenReturn("any password hash"); From 73d5b205e82a41c247d4fbc5ac4cef855d992b4c Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 00:56:39 +0100 Subject: [PATCH 03/10] account should be valid for valid credentials --- .../de/ci/exam/project/AccountServiceTest.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index f5ab438..1e5d96b 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -1,10 +1,11 @@ package hs.fulda.de.ci.exam.project; import org.junit.Before; +import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; public class AccountServiceTest { private static final String PASSWORD = "password"; @@ -26,6 +27,16 @@ public class AccountServiceTest { accountService = new AccountService(accountRepository, passwordEncoder); } + @Test + public void shouldBeValidForValidCredentials(){ + boolean accountIsValid = accountService.isValidAccount(ENABLED_USER.getId(), PASSWORD); + assertTrue(accountIsValid); + + verify(accountRepository).findById(ENABLED_USER.getId()); + + verify(passwordEncoder).encode(PASSWORD); + } + private AccountRepository createAccountRepository() { AccountRepository mock = mock(AccountRepository.class); when(mock.findById(ENABLED_USER.getId())).thenReturn(ENABLED_USER); From 66f1b649387712683f1494f4ab5bddbe7e81adc0 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 01:11:20 +0100 Subject: [PATCH 04/10] account should be invalid for invalid credentials --- .../ci/exam/project/AccountServiceTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index 1e5d96b..b1c1681 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -2,7 +2,9 @@ package hs.fulda.de.ci.exam.project; import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @@ -37,6 +39,26 @@ public class AccountServiceTest { verify(passwordEncoder).encode(PASSWORD); } + @Test + public void shouldBEInvalidForInvalidId() { + boolean accountIsValid = accountService.isValidAccount("invalid id", PASSWORD); + assertFalse(accountIsValid); + + InOrder inOrder = inOrder(accountRepository, passwordEncoder); + inOrder.verify(accountRepository).findById("invalid id"); + inOrder.verify(passwordEncoder, never()).encode(anyString()); + } + + @Test + public void shouldBeInvalidForInvalid(){ + boolean accountIsValid = accountService.isValidAccount("invalid id", PASSWORD); + assertFalse(accountIsValid); + + InOrder inOrder = inOrder(accountRepository, passwordEncoder); + inOrder.verify(accountRepository).findById("invalid id"); + inOrder.verify(passwordEncoder, never()).encode(anyString()); + } + private AccountRepository createAccountRepository() { AccountRepository mock = mock(AccountRepository.class); when(mock.findById(ENABLED_USER.getId())).thenReturn(ENABLED_USER); From ed3a1b72525cd3fef74e9e104351da4230db08cd Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 01:18:07 +0100 Subject: [PATCH 05/10] account should be invalid for disabled user --- .../hs/fulda/de/ci/exam/project/AccountServiceTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index b1c1681..90d1d69 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -59,6 +59,15 @@ public class AccountServiceTest { inOrder.verify(passwordEncoder, never()).encode(anyString()); } + @Test + public void shouldBeInvalidForDisabledUser(){ + boolean accountIsValid = + accountService.isValidAccount(DISABLED_USER.getId(), PASSWORD); + assertFalse(accountIsValid); + + verify(accountRepository).findById(DISABLED_USER.getId()); + verify(passwordEncoder, never()).encode(anyString()); + } private AccountRepository createAccountRepository() { AccountRepository mock = mock(AccountRepository.class); when(mock.findById(ENABLED_USER.getId())).thenReturn(ENABLED_USER); From 646a6a0342e54733151dbbdd719f83c85e4a8295 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 01:29:48 +0100 Subject: [PATCH 06/10] account should be invalid for invalid password --- .../de/ci/exam/project/AccountServiceTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index 90d1d69..e80e849 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -2,10 +2,10 @@ package hs.fulda.de.ci.exam.project; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.InOrder; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @@ -68,6 +68,19 @@ public class AccountServiceTest { verify(accountRepository).findById(DISABLED_USER.getId()); verify(passwordEncoder, never()).encode(anyString()); } + + @Test + public void shouldBeInvalidForInvalidPassword() { + boolean accountIsValid = + accountService.isValidAccount(ENABLED_USER.getId(), "invalid"); + assertFalse(accountIsValid); + + ArgumentCaptor passwordCaptor = ArgumentCaptor.forClass(String.class); + + verify(passwordEncoder).encode(passwordCaptor.capture()); + assertEquals("invalid", passwordCaptor.getValue()); + } + private AccountRepository createAccountRepository() { AccountRepository mock = mock(AccountRepository.class); when(mock.findById(ENABLED_USER.getId())).thenReturn(ENABLED_USER); From 36e9726d97cdb40b8f9909f586fb99d60971f496 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 02:05:45 +0100 Subject: [PATCH 07/10] Should Not Create Account when Id is null --- .../hs/fulda/de/ci/exam/project/Account.java | 15 +++++++++++++ .../de/ci/exam/project/AccountService.java | 21 +++++++++++++++++++ .../ci/exam/project/AccountServiceTest.java | 12 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/main/java/hs/fulda/de/ci/exam/project/Account.java b/src/main/java/hs/fulda/de/ci/exam/project/Account.java index 7097e7e..882db6a 100644 --- a/src/main/java/hs/fulda/de/ci/exam/project/Account.java +++ b/src/main/java/hs/fulda/de/ci/exam/project/Account.java @@ -75,6 +75,21 @@ public class Account { accountRepository.addPersonalDetails(person, id); } + public void validateId() { + if(this.id.isBlank()) + throw new RuntimeException(("Id Cannot be null or empty")); + } + + public void validatePassword(){ + if(this.password.isBlank()) + throw new RuntimeException(("Id Cannot be null or empty")); + } + + public void validateAccountStatus(){ + if(this.status.equals(null)) + throw new RuntimeException(("Id Cannot be null or empty")); + } + } class PasswordEncoder{ String encode(String password){ diff --git a/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java b/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java index 789ecba..051e0b9 100644 --- a/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java +++ b/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java @@ -1,5 +1,7 @@ package hs.fulda.de.ci.exam.project; +import java.util.Date; + public class AccountService { private final AccountRepository accountRepository; private final PasswordEncoder passwordEncoder; @@ -21,4 +23,23 @@ public class AccountService { String encodedPassword = passwordEncoder.encode(password); return encodedPassword.equals(account.getPasswordHash()); } + public void validateAccount(Account account){ + account.validateAccountStatus(); + account.validateId(); + account.validatePassword(); + } + + public void checkIfAccountAlreadyExist(Account account){ + if(accountRepository.checkIfAccountAlreadyExist(account)){ + throw new RuntimeException("Account Already Exists"); + } + } + public void createAccount(String id, String password, Account.AccountStatus accountStatus){ + Account account = new Account(id, password, accountStatus); + validateAccount(account); + checkIfAccountAlreadyExist(account); + accountRepository.save(account); + } + + } diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index e80e849..326576a 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -2,9 +2,13 @@ package hs.fulda.de.ci.exam.project; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.DisplayName; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; +import java.util.ArrayList; +import java.util.Date; + import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @@ -95,4 +99,12 @@ public class AccountServiceTest { return mock; } + @Test + @DisplayName("Should Not Create Account when Id is null") + public void shouldThrowRuntimeExceptionWhenIdIsNull(){ + assertThrows(RuntimeException.class, () -> { + accountService.createAccount(null, "pwd", Account.AccountStatus.ACTIVE); + }); + } + } From 79024b050421fc9ddbc2e902803afddf5abdbe9d Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 02:07:32 +0100 Subject: [PATCH 08/10] Should Not Create Account when Password is blank or null --- .../hs/fulda/de/ci/exam/project/AccountServiceTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index 326576a..f9cd7b5 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -107,4 +107,12 @@ public class AccountServiceTest { }); } + @Test + @DisplayName("Should Not Create Account when password is blank") + public void shouldThrowRuntimeExceptionWhenPasswordIsNull(){ + assertThrows(RuntimeException.class, () -> { + accountService.createAccount("John", "", Account.AccountStatus.ACTIVE); + }); + } + } From 43029d27bee731430de0aaaa684f519d467e48a6 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 02:08:45 +0100 Subject: [PATCH 09/10] should Not Create Account when Status is null --- .../hs/fulda/de/ci/exam/project/AccountServiceTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index f9cd7b5..dfbe67e 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -115,4 +115,12 @@ public class AccountServiceTest { }); } + @Test + @DisplayName("Should Not Create Account when status is null") + public void shouldThrowRuntimeExceptionWhenStatusIsNull(){ + assertThrows(RuntimeException.class, () -> { + accountService.createAccount("John", "", null); + }); + } + } From 0ebcc656f863464819bae23b464a86de2050f9e4 Mon Sep 17 00:00:00 2001 From: Sona Markosyan Date: Fri, 11 Feb 2022 02:19:16 +0100 Subject: [PATCH 10/10] verify create account --- .../de/ci/exam/project/AccountRepository.java | 7 ++++++- .../fulda/de/ci/exam/project/AccountService.java | 3 ++- .../de/ci/exam/project/AccountServiceTest.java | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java b/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java index 90a96db..6cec755 100644 --- a/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java +++ b/src/main/java/hs/fulda/de/ci/exam/project/AccountRepository.java @@ -25,10 +25,15 @@ public class AccountRepository { public Collection findAll() { return accountList.values(); } - public void save(Account account){ + public boolean save(Account account){ accountList.put(generateKey(account), account); + return true; } public void addPersonalDetails(Person person, String id){ personalInfo.put(accountList.get(id), person); } + + public void delete(Account account) { + accountList.remove(generateKey(account)); + } } diff --git a/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java b/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java index 051e0b9..814d4c2 100644 --- a/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java +++ b/src/main/java/hs/fulda/de/ci/exam/project/AccountService.java @@ -34,11 +34,12 @@ public class AccountService { throw new RuntimeException("Account Already Exists"); } } - public void createAccount(String id, String password, Account.AccountStatus accountStatus){ + public boolean createAccount(String id, String password, Account.AccountStatus accountStatus){ Account account = new Account(id, password, accountStatus); validateAccount(account); checkIfAccountAlreadyExist(account); accountRepository.save(account); + return true; } diff --git a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java index dfbe67e..3d1d7dd 100644 --- a/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java +++ b/src/test/java/hs/fulda/de/ci/exam/project/AccountServiceTest.java @@ -9,6 +9,8 @@ import org.mockito.InOrder; import java.util.ArrayList; import java.util.Date; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.CoreMatchers.is; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @@ -123,4 +125,16 @@ public class AccountServiceTest { }); } + @Test + public void verifyCreateAccount() { + + when(accountRepository.save(any(Account.class))).thenReturn(true); + + assertTrue(accountService.createAccount("John", "pwd", Account.AccountStatus.ACTIVE)); + + verify(accountRepository).save(any(Account.class)); + verify(accountRepository, times(1)).checkIfAccountAlreadyExist(any(Account.class)); + verify(accountRepository, never()).delete(any(Account.class)); + } + }