package com.mailserver.controller; import com.mailserver.config.MailDomains; import com.mailserver.domain.User; import com.mailserver.service.MailDirectory; import com.mailserver.service.MailLists; import com.mailserver.service.UserService; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** Service API for Jambotron: token only; account created once with a password; switched off → out of the lists. */ class ServiceControllerTest { private static final String AUTH = "Bearer s3cret-token"; private final UserService users = mock(UserService.class); private final MailLists lists = mock(MailLists.class); private final MailDomains domains = new MailDomains("jambocheck.com", ""); private final com.mailserver.service.MailboxAccess access = mock(com.mailserver.service.MailboxAccess.class); private final MailDirectory directory = new MailDirectory(users, lists, domains, access); private final User existing = user(7L, "jambotronpw@jambocheck.com"); private final com.mailserver.config.MailAdmins admins = new com.mailserver.config.MailAdmins("", "", domains); ServiceControllerTest() { when(users.findOptional(anyString())).thenReturn(Mono.empty()); when(users.findOptional("jambotronpw@jambocheck.com")).thenReturn(Mono.just(existing)); when(lists.exists(anyString())).thenReturn(Mono.just(false)); when(lists.listsOf(anyLong())).thenReturn(Flux.just("alerts-prod@jambocheck.com")); when(lists.removeEverywhere(anyLong())).thenReturn(Mono.just(1L)); when(access.removeEverywhere(anyLong())).thenReturn(Mono.just(1L)); when(users.register(anyString(), anyString(), any())).thenAnswer(i -> Mono.just(user(8L, i.getArgument(0)))); when(users.setActive(any(), any(Boolean.class))).thenAnswer(i -> { User u = i.getArgument(0); u.setActive(i.getArgument(1)); return Mono.just(u); }); when(users.setPassword(any(), anyString())).thenAnswer(i -> Mono.just((User) i.getArgument(0))); when(users.setAdmin(any(), any(Boolean.class))).thenAnswer(i -> { User u = i.getArgument(0); u.setAdmin(i.getArgument(1)); return Mono.just(u); }); } // Jambotron ADMIN → mail administrator (Settings → MAILBOXES), and back @Test void jambotronMakesAMailboxAdministratorAndTakesItBack() { assertThat(admins.isAdmin("jambotronpw@jambocheck.com")).isFalse(); var made = api("s3cret-token").saveAccount(AUTH, "jambotronpw@jambocheck.com", Mono.just(new ServiceController.AccountRequest(null, true, true))).block(); assertThat(made.getBody().account().admin()).isTrue(); assertThat(admins.isAdmin("JambotronPW@jambocheck.com")).isTrue(); api("s3cret-token").saveAccount(AUTH, "jambotronpw@jambocheck.com", Mono.just(new ServiceController.AccountRequest(null, true, false))).block(); assertThat(admins.isAdmin("jambotronpw@jambocheck.com")).isFalse(); assertThat(admins.isAdmin("admin@jambocheck.com")).isTrue(); } private ServiceController api(String token) { return new ServiceController(token, users, lists, directory, access, admins); } @Test void offWithoutTokenWrongTokenRefused() { assertThat(status(() -> api("").account(AUTH, "jambotronpw@jambocheck.com"))).isEqualTo(HttpStatus.NOT_FOUND); assertThat(status(() -> api("s3cret-token").account("Bearer nope", "jambotronpw@jambocheck.com"))).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(status(() -> api("s3cret-token").account(null, "jambotronpw@jambocheck.com"))).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(api("s3cret-token").account(AUTH, "jambotronpw@jambocheck.com").block().lists()) .containsExactly("alerts-prod@jambocheck.com"); } @Test void newAccountGetsPasswordOnceExistingDoesNot() { var created = api("s3cret-token").saveAccount(AUTH, "moder@jambocheck.com", Mono.just(new ServiceController.AccountRequest("Moder", true, null))).block(); assertThat(created.getStatusCode().value()).isEqualTo(201); assertThat(created.getBody().password()).hasSizeGreaterThan(20); var again = api("s3cret-token").saveAccount(AUTH, "jambotronpw@jambocheck.com", Mono.just(new ServiceController.AccountRequest(null, null, null))).block(); assertThat(again.getStatusCode().value()).isEqualTo(200); assertThat(again.getBody().password()).isNull(); verify(lists, never()).removeEverywhere(anyLong()); assertThat(status(() -> api("s3cret-token").saveAccount(AUTH, "x@gmail.com", Mono.empty()))).isEqualTo(HttpStatus.BAD_REQUEST); } @Test void switchedOffLeavesEveryList() { var off = api("s3cret-token").saveAccount(AUTH, "jambotronpw@jambocheck.com", Mono.just(new ServiceController.AccountRequest(null, false, null))).block(); assertThat(off.getBody().account().active()).isFalse(); verify(lists).removeEverywhere(7L); verify(access).removeEverywhere(7L); var reset = api("s3cret-token").password(AUTH, "jambotronpw@jambocheck.com").block(); assertThat(reset.password()).isNotBlank(); verify(users).setPassword(existing, reset.password()); } private static HttpStatus status(Runnable call) { Throwable error = catchThrowable(call::run); assertThat(error).isInstanceOf(ResponseStatusException.class); return HttpStatus.valueOf(((ResponseStatusException) error).getStatusCode().value()); } private static User user(Long id, String email) { User user = new User(); user.setId(id); user.setEmail(email); user.setPassword("hash"); return user; } }