#1037 Improve architecture of registration methods (#236)

* #1037 Improve architecture of registration methods
- Introduce parameters classes for each registration method
- RegistrationMethod has constants with the required parameters class -> no longer need to have a RegistrationExecutorProvider class that needs to be injected everywhere, let AsyncRegister be the only one to worry about which class will perform the registration
- Fix inheritance of password registration types - previously two-factor auth registration inherited from password registration directly

* Create matcher which checks for equality via reflections
- Allow to perform equality check on objects with default equals() method
This commit is contained in:
ljacqu
2017-03-20 08:19:52 +01:00
committed by GitHub
parent 7f16e80442
commit 9a9d0974f8
31 changed files with 820 additions and 393 deletions
@@ -1,13 +1,17 @@
package fr.xephi.authme.command.executable.register;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.mail.EmailService;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.register.RegisterSecondaryArgument;
import fr.xephi.authme.process.register.RegistrationType;
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
import fr.xephi.authme.process.register.executors.RegistrationExecutorProvider;
import fr.xephi.authme.process.register.executors.EmailRegisterParams;
import fr.xephi.authme.process.register.executors.PasswordRegisterParams;
import fr.xephi.authme.process.register.executors.RegistrationMethod;
import fr.xephi.authme.process.register.executors.RegistrationParameters;
import fr.xephi.authme.process.register.executors.TwoFactorRegisterParams;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
@@ -16,6 +20,9 @@ import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -24,10 +31,16 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
@@ -57,9 +70,6 @@ public class RegisterCommandTest {
@Mock
private ValidationService validationService;
@Mock
private RegistrationExecutorProvider registrationExecutorProvider;
@BeforeClass
public static void setup() {
TestHelper.setupLogger();
@@ -90,14 +100,13 @@ public class RegisterCommandTest {
// given
given(commonService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.TWO_FACTOR);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getTwoFactorRegisterExecutor(player)).willReturn(executor);
// when
command.executeCommand(player, Collections.emptyList());
// then
verify(management).performRegister(player, executor);
verify(management).performRegister(eq(RegistrationMethod.TWO_FACTOR_REGISTRATION),
argThat(isEqualTo(TwoFactorRegisterParams.of(player))));
verifyZeroInteractions(emailService);
}
@@ -208,8 +217,6 @@ public class RegisterCommandTest {
given(commonService.getProperty(RegistrationSettings.REGISTER_SECOND_ARGUMENT)).willReturn(RegisterSecondaryArgument.CONFIRMATION);
given(emailService.hasAllInformation()).willReturn(true);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getEmailRegisterExecutor(player, playerMail)).willReturn(executor);
// when
command.executeCommand(player, Arrays.asList(playerMail, playerMail));
@@ -217,7 +224,8 @@ public class RegisterCommandTest {
// then
verify(validationService).validateEmail(playerMail);
verify(emailService).hasAllInformation();
verify(management).performRegister(player, executor);
verify(management).performRegister(eq(RegistrationMethod.EMAIL_REGISTRATION),
argThat(isEqualTo(EmailRegisterParams.of(player, playerMail))));
}
@Test
@@ -239,14 +247,13 @@ public class RegisterCommandTest {
public void shouldPerformPasswordRegistration() {
// given
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getPasswordRegisterExecutor(player, "myPass", null)).willReturn(executor);
// when
command.executeCommand(player, Collections.singletonList("myPass"));
// then
verify(management).performRegister(player, executor);
verify(management).performRegister(eq(RegistrationMethod.PASSWORD_REGISTRATION),
argThat(isEqualTo(PasswordRegisterParams.of(player, "myPass", null))));
}
@Test
@@ -257,15 +264,14 @@ public class RegisterCommandTest {
String email = "email@example.org";
given(validationService.validateEmail(email)).willReturn(true);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getPasswordRegisterExecutor(player, "myPass", email)).willReturn(executor);
// when
command.executeCommand(player, Arrays.asList("myPass", email));
// then
verify(validationService).validateEmail(email);
verify(management).performRegister(player, executor);
verify(management).performRegister(eq(RegistrationMethod.PASSWORD_REGISTRATION),
argThat(isEqualTo(PasswordRegisterParams.of(player, "myPass", email))));
}
@Test
@@ -292,14 +298,64 @@ public class RegisterCommandTest {
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationType.PASSWORD);
given(commonService.getProperty(RegistrationSettings.REGISTER_SECOND_ARGUMENT)).willReturn(RegisterSecondaryArgument.EMAIL_OPTIONAL);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getPasswordRegisterExecutor(eq(player), anyString(), eq(null))).willReturn(executor);
// when
command.executeCommand(player, Collections.singletonList("myPass"));
// then
verify(registrationExecutorProvider).getPasswordRegisterExecutor(player, "myPass", null);
verify(management).performRegister(player, executor);
verify(management).performRegister(eq(RegistrationMethod.PASSWORD_REGISTRATION),
argThat(isEqualTo(PasswordRegisterParams.of(player, "myPass", null))));
}
// TODO ljacqu 20170317: Document and extract as util
private static <P extends RegistrationParameters> Matcher<P> isEqualTo(P expected) {
return new TypeSafeMatcher<P>() {
@Override
protected boolean matchesSafely(RegistrationParameters item) {
assertAreParamsEqual(expected, item);
return true;
}
@Override
public void describeTo(Description description) {
description.appendText("parameters " + expected);
}
};
}
private static void assertAreParamsEqual(RegistrationParameters lhs, RegistrationParameters rhs) {
if (lhs.getClass() != rhs.getClass()) {
fail("Params classes don't match, got " + lhs.getClass().getSimpleName()
+ " and " + rhs.getClass().getSimpleName());
}
List<Field> fieldsToCheck = getFields(lhs);
for (Field field : fieldsToCheck) {
Object lhsValue = ReflectionTestUtils.getFieldValue(field, lhs);
Object rhsValue = ReflectionTestUtils.getFieldValue(field, rhs);
if (!Objects.equals(lhsValue, rhsValue)) {
fail("Field '" + field.getName() + "' does not have same value: '"
+ lhsValue + "' vs. '" + rhsValue + "'");
}
}
}
private static List<Field> getFields(RegistrationParameters params) {
List<Field> fields = new ArrayList<>();
Class<?> currentClass = params.getClass();
while (currentClass != null) {
for (Field f : currentClass.getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers())) {
fields.add(f);
}
}
if (currentClass == RegistrationParameters.class) {
break;
}
currentClass = currentClass.getSuperclass();
}
return fields;
}
}