Skip to content
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
18 changes: 17 additions & 1 deletion src/main/java/com/wcc/platform/service/MentorshipService.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class MentorshipService {
private static final String EUROPE_LONDON = "Europe/London";
private static final MentorshipCycle ACTIVE_LONG_TERM =
new MentorshipCycle(MentorshipType.LONG_TERM, Month.MARCH);
private static final int MINIMUM_HOURS = 2;

private final MentorRepository mentorRepository;
private final MemberRepository memberRepository;
Expand Down Expand Up @@ -95,7 +96,7 @@ public Mentor create(final Mentor mentor) {
throw new DuplicatedMemberException(mentorExists.get().getEmail());
}
}

validateMentorCommitment(mentor);
return mentorRepository.create(mentor);
}

Expand Down Expand Up @@ -227,6 +228,21 @@ public Mentor updateMentor(final Long mentorId, final MentorDto mentorDto) {
final var mentor = mentorOptional.orElseThrow(() -> new MemberNotFoundException(mentorId));

final Mentor updatedMentor = mentorDto.merge(mentor);
validateMentorCommitment(updatedMentor);
return mentorRepository.update(mentorId, updatedMentor);
}

private void validateMentorCommitment(final Mentor mentor) {
final var menteeSection = mentor.getMenteeSection();
final boolean isLongTermMentorship =
menteeSection.mentorshipType().contains(MentorshipType.LONG_TERM);
final boolean hasInsufficientHours =
menteeSection.availability().stream()
.anyMatch(availability -> availability.hours() < MINIMUM_HOURS);

if (isLongTermMentorship && hasInsufficientHours) {
throw new IllegalArgumentException(
"Long-term mentorship requires mentor to commit at least 2 hours per month.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,38 @@ public static MentorDto createMentorDtoTest(final Long mentorId, final MemberTyp
.build();
}

/** Factory test to create MemberDto object with mentorshipTypes and availabilities params. */
public static MentorDto createMentorDtoTest(
final Long mentorId,
final MemberType type,
final List<MentorshipType> mentorshipTypes,
final List<MentorMonthAvailability> availabilities) {
return MentorDto.mentorDtoBuilder()
.id(mentorId)
.fullName("fullName " + type.name())
.position("position " + type.name())
.email("email@" + type.name().toLowerCase())
.slackDisplayName("slackDisplayName")
.country(new Country("ES", "Spain"))
.city("City")
.companyName("Company name")
.images(List.of(new Image("image.png", "alt image", ImageType.MOBILE)))
.network(List.of(new SocialNetwork(SocialNetworkType.GITHUB, "collaborator_link_updated")))
.profileStatus(ProfileStatus.ACTIVE)
.bio("Mentor bio")
.spokenLanguages(List.of("English"))
.skills(
new Skills(
2,
List.of(TechnicalArea.BACKEND, TechnicalArea.FRONTEND),
List.of(Languages.JAVASCRIPT),
List.of(MentorshipFocusArea.GROW_BEGINNER_TO_MID)))
.menteeSection(
new MenteeSection(
mentorshipTypes, availabilities, "ideal mentee description", "additional"))
.build();
}

/** Test factory for updated Mentor. */
public static Mentor createUpdatedMentorTest(final Mentor mentor, final MentorDto mentorDto) {

Expand Down Expand Up @@ -137,6 +169,39 @@ public static Mentor createUpdatedMentorTest(final Mentor mentor, final MentorDt
.build();
}

/** Test factory for updated Mentor with mentorship types and availabilities params. */
public static Mentor createUpdatedMentorTest(
final Mentor mentor,
final MentorDto mentorDto,
final List<MentorshipType> mentorshipTypes,
final List<MentorMonthAvailability> availabilities) {

return Mentor.mentorBuilder()
.id(mentor.getId())
.fullName(mentorDto.getFullName())
.position(mentorDto.getPosition())
.email(mentorDto.getEmail())
.slackDisplayName(mentorDto.getSlackDisplayName())
.country(mentorDto.getCountry())
.images(mentorDto.getImages())
.profileStatus(ProfileStatus.ACTIVE)
.bio("Mentor bio UPDATED")
.spokenLanguages(List.of("English", "German"))
.skills(
new Skills(
5,
List.of(TechnicalArea.BACKEND),
List.of(Languages.JAVASCRIPT, Languages.C_LANGUAGE),
List.of(MentorshipFocusArea.CHANGE_SPECIALISATION)))
.menteeSection(
new MenteeSection(
mentorshipTypes,
availabilities,
"ideal mentee description UPDATED",
"additional UPDATED"))
.build();
}

/** Creates a test MemberProfilePicture with associated Resource. */
public static MemberProfilePicture createMemberProfilePictureTest(final Long memberId) {
return MemberProfilePicture.builder()
Expand Down
163 changes: 158 additions & 5 deletions src/test/java/com/wcc/platform/service/MentorshipServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import static org.mockito.Mockito.withSettings;

import com.wcc.platform.domain.cms.attributes.ImageType;
import com.wcc.platform.domain.cms.pages.mentorship.MenteeSection;
import com.wcc.platform.domain.cms.pages.mentorship.MentorMonthAvailability;
import com.wcc.platform.domain.exceptions.DuplicatedMemberException;
import com.wcc.platform.domain.exceptions.MemberNotFoundException;
import com.wcc.platform.domain.platform.member.Member;
Expand Down Expand Up @@ -76,9 +78,9 @@ void setUp() {
void whenCreateGivenMentorAlreadyExistsThenThrowDuplicatedMemberException() {
var mentor = mock(Mentor.class);
when(mentor.getId()).thenReturn(1L);
when(mentorRepository.findById(1L)).thenReturn(Optional.of(mentor));
when(mentor.getEmail()).thenReturn("test@test.com");
when(memberRepository.findByEmail("test@test.com")).thenReturn(Optional.empty());
when(mentorRepository.findById(1L)).thenReturn(Optional.of(mentor));

assertThrows(DuplicatedMemberException.class, () -> service.create(mentor));
verify(mentorRepository, never()).create(any());
Expand All @@ -87,7 +89,9 @@ void whenCreateGivenMentorAlreadyExistsThenThrowDuplicatedMemberException() {
@Test
void whenCreateGivenMentorDoesNotExistThenCreateMentor() {
var mentor = mock(Mentor.class);
var menteeSection = mock(MenteeSection.class);
when(mentor.getId()).thenReturn(2L);
when(mentor.getMenteeSection()).thenReturn(menteeSection);
when(mentor.getEmail()).thenReturn("newmentor@test.com");
when(memberRepository.findByEmail("newmentor@test.com")).thenReturn(Optional.empty());
when(mentorRepository.findById(2L)).thenReturn(Optional.empty());
Expand All @@ -100,6 +104,80 @@ void whenCreateGivenMentorDoesNotExistThenCreateMentor() {
verify(mentorRepository).create(mentor);
}

@Test
@DisplayName(
"Given mentor with long-term mentorship and 2+ hours commitment When creating Then create"
+ " mentor and return it")
void testCreateAvailableLongTermMentor() {
var mentor = mock(Mentor.class);
var menteeSection = mock(MenteeSection.class);
when(mentor.getId()).thenReturn(2L);
when(mentor.getMenteeSection()).thenReturn(menteeSection);
when(menteeSection.mentorshipType())
.thenReturn(List.of(MentorshipType.AD_HOC, MentorshipType.LONG_TERM));
when(menteeSection.availability())
.thenReturn(
List.of(
new MentorMonthAvailability(Month.JANUARY, 3),
new MentorMonthAvailability(Month.FEBRUARY, 4)));
when(mentorRepository.findById(2L)).thenReturn(Optional.empty());
when(mentorRepository.create(mentor)).thenReturn(mentor);

var result = service.create(mentor);

assertEquals(mentor, result);
verify(mentorRepository).create(mentor);
}

@Test
@DisplayName(
"Given mentor with adhoc mentorship and under 2 hours commitment When creating Then create"
+ " mentor and return it")
void testCreateUnavailableAdHocMentor() {
var mentor = mock(Mentor.class);
var menteeSection = mock(MenteeSection.class);
when(mentor.getId()).thenReturn(2L);
when(mentor.getMenteeSection()).thenReturn(menteeSection);
when(menteeSection.mentorshipType()).thenReturn(List.of(MentorshipType.AD_HOC));
when(menteeSection.availability())
.thenReturn(
List.of(
new MentorMonthAvailability(Month.JANUARY, 1),
new MentorMonthAvailability(Month.FEBRUARY, 1)));
when(mentorRepository.findById(2L)).thenReturn(Optional.empty());
when(mentorRepository.create(mentor)).thenReturn(mentor);

var result = service.create(mentor);

assertEquals(mentor, result);
verify(mentorRepository).create(mentor);
}

@Test
@DisplayName(
"Given mentor with long-term mentorship and 2+ hours commitment When creating the"
+ " mentor Then throw IllegalArgumentException")
void testCreateUnavailableLongTermMentor() {
var mentor = mock(Mentor.class);
var menteeSection = mock(MenteeSection.class);
when(mentor.getId()).thenReturn(1L);
when(mentor.getMenteeSection()).thenReturn(menteeSection);
when(menteeSection.mentorshipType())
.thenReturn(List.of(MentorshipType.AD_HOC, MentorshipType.LONG_TERM));
when(menteeSection.availability())
.thenReturn(
List.of(
new MentorMonthAvailability(Month.JANUARY, 1),
new MentorMonthAvailability(Month.FEBRUARY, 2)));
when(mentorRepository.findById(1L)).thenReturn(Optional.empty());

var expectedMsg = "Long-term mentorship requires mentor to commit at least 2 hours per month.";
var exception = assertThrows(IllegalArgumentException.class, () -> service.create(mentor));

assertEquals(expectedMsg, exception.getMessage());
verify(mentorRepository, never()).create(any());
}

@Test
void whenGetAllMentorsGivenCycleClosedThenReturnDtosWithoutCycle() {
var mentor = mock(Mentor.class, withSettings().defaultAnswer(RETURNS_DEEP_STUBS));
Expand Down Expand Up @@ -238,6 +316,79 @@ void testUpdateMentorIllegalIdMismatch() {
verify(mentorRepository, never()).update(anyLong(), any());
}

@Test
@DisplayName(
"Given mentor with long-term mentorship and 2+ hours commitment When updating the mentor"
+ " Then update and return it")
void testUpdateLongTermMentorAvailableTwoHours() {
final var updatedMentorWithAvailabilities =
createUpdatedMentorTest(
mentor,
mentorDto,
List.of(MentorshipType.AD_HOC, MentorshipType.LONG_TERM),
List.of(
new MentorMonthAvailability(Month.JANUARY, 2),
new MentorMonthAvailability(Month.FEBRUARY, 2)));
long mentorId = 1L;
when(mentorRepository.findById(mentorId)).thenReturn(Optional.of(mentor));
when(mentorRepository.update(anyLong(), any())).thenReturn(updatedMentorWithAvailabilities);
Member result = service.updateMentor(mentorId, mentorDto);

assertEquals(updatedMentorWithAvailabilities, result);
verify(mentorRepository).findById(mentorId);
verify(mentorRepository).update(anyLong(), any());
}

@Test
@DisplayName(
"Given mentor with adhoc mentorship and under 2 hours commitment When updating the mentor"
+ " Then update and return it")
void testUpdateUnavailableAdHocMentor() {
final var updatedMentorWithAvailabilities =
createUpdatedMentorTest(
mentor,
mentorDto,
List.of(MentorshipType.AD_HOC),
List.of(
new MentorMonthAvailability(Month.JANUARY, 1),
new MentorMonthAvailability(Month.FEBRUARY, 0)));
long mentorId = 1L;
when(mentorRepository.findById(mentorId)).thenReturn(Optional.of(mentor));
when(mentorRepository.update(anyLong(), any())).thenReturn(updatedMentorWithAvailabilities);

Member result = service.updateMentor(mentorId, mentorDto);

assertEquals(updatedMentorWithAvailabilities, result);
verify(mentorRepository).findById(mentorId);
verify(mentorRepository).update(anyLong(), any());
}

@Test
@DisplayName(
"Given mentor with long-term mentorship and under 2 hours commitment"
+ " When updating the mentor Then throw IllegalArgumentException")
void testUpdateUnavailableLongTermMentorIllegalArgumentException() {
long mentorId = 1L;
MentorDto newMentorDto =
createMentorDtoTest(
1L,
MemberType.DIRECTOR,
List.of(MentorshipType.AD_HOC, MentorshipType.LONG_TERM),
List.of(
new MentorMonthAvailability(Month.JANUARY, 2),
new MentorMonthAvailability(Month.FEBRUARY, 0)));
when(mentorRepository.findById(mentorId)).thenReturn(Optional.of(mentor));

var expectedMsg = "Long-term mentorship requires mentor to commit at least 2 hours per month.";
var exception =
assertThrows(
IllegalArgumentException.class, () -> service.updateMentor(mentorId, newMentorDto));
assertEquals(expectedMsg, exception.getMessage());

verify(mentorRepository).findById(anyLong());
verify(mentorRepository, never()).update(anyLong(), any());
}

@Test
@DisplayName(
"Given mentor with profile picture, when getAllMentors is called, then images list should"
Expand Down Expand Up @@ -315,18 +466,20 @@ void shouldUseExistingMemberWhenMentorEmailAlreadyExists() {
when(mentor.getFullName()).thenReturn("Existing Member as Mentor");
when(mentor.getPosition()).thenReturn("Software Engineer");
when(mentor.getSlackDisplayName()).thenReturn("@existing");
when(mentor.getCountry()).thenReturn(mock(com.wcc.platform.domain.cms.attributes.Country.class));
when(mentor.getCountry())
.thenReturn(mock(com.wcc.platform.domain.cms.attributes.Country.class));
when(mentor.getCity()).thenReturn("New York");
when(mentor.getCompanyName()).thenReturn("Tech Corp");
when(mentor.getImages()).thenReturn(List.of());
when(mentor.getNetwork()).thenReturn(List.of());
when(mentor.getProfileStatus())
.thenReturn(com.wcc.platform.domain.platform.member.ProfileStatus.ACTIVE);
when(mentor.getSkills()).thenReturn(mock(com.wcc.platform.domain.platform.mentorship.Skills.class));
when(mentor.getSkills())
.thenReturn(mock(com.wcc.platform.domain.platform.mentorship.Skills.class));
when(mentor.getSpokenLanguages()).thenReturn(List.of("English"));
when(mentor.getBio()).thenReturn("Bio");
when(mentor.getMenteeSection()).thenReturn(
mock(com.wcc.platform.domain.cms.pages.mentorship.MenteeSection.class));
when(mentor.getMenteeSection())
.thenReturn(mock(com.wcc.platform.domain.cms.pages.mentorship.MenteeSection.class));
when(mentor.getFeedbackSection()).thenReturn(null);
when(mentor.getResources()).thenReturn(null);

Expand Down
Loading