package com.atlassian.stash.internal.audit;

import com.atlassian.bitbucket.audit.AuditEntry;
import com.atlassian.bitbucket.audit.Priority;
import com.atlassian.bitbucket.event.auth.AuthenticationFailureEvent;
import com.atlassian.bitbucket.event.auth.AuthenticationSuccessEvent;
import com.atlassian.bitbucket.event.audit.AuditEvent;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.auth.AuthenticationException;
import com.atlassian.bitbucket.user.UserService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

public class AuthenticationEventListenerTest extends AbstractAuditEventListenerTest {

    private static final String AUTH_METHOD = "magic";
    private static final String EXCEPTION_MESSAGE = "something went horribly wrong!";

    @Mock
    private AuthenticationException exception;
    @Mock
    private ApplicationUser user;
    @Mock
    private UserService userService;
    @InjectMocks
    private AuthenticationEventListener listener;

    @Before
    public void setup() {
        when(userService.getUserByName(USERNAME)).thenReturn(user);
        when(user.getName()).thenReturn(USERNAME);
        when(exception.getLocalizedMessage()).thenReturn(EXCEPTION_MESSAGE);
    }

    @Test
    public void testOnAuthenticationFailure() throws Exception {
        listener.onAuthenticationFailure(new AuthenticationFailureEvent(this, USERNAME, AUTH_METHOD, exception));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();
        assertContains(entry.getDetails(), EXCEPTION_MESSAGE, AUTH_METHOD);
        assertEquals(USERNAME, entry.getTarget());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnAuthenticationFailureNoException() throws Exception {
        listener.onAuthenticationFailure(new AuthenticationFailureEvent(this, null, AUTH_METHOD, null));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();
        assertContains(entry.getDetails(), AUTH_METHOD);
        assertEquals("<anonymous>", entry.getTarget());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnAuthenticationFailureNoUserForUsername() throws Exception {
        listener.onAuthenticationFailure(new AuthenticationFailureEvent(this, "no-such-user", AUTH_METHOD, exception));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();
        assertContains(entry.getDetails(), EXCEPTION_MESSAGE, AUTH_METHOD);
        assertEquals("no-such-user", entry.getTarget());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnAuthenticationFailureNoUsername() throws Exception {
        listener.onAuthenticationFailure(new AuthenticationFailureEvent(this, null, AUTH_METHOD, exception));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();
        assertContains(entry.getDetails(), EXCEPTION_MESSAGE, AUTH_METHOD);
        assertEquals("<anonymous>", entry.getTarget());
        assertEventCommonDetails(event, Priority.HIGH);
    }

    @Test
    public void testOnAuthenticationSuccess() throws Exception {
        listener.onAuthenticationSuccess(new AuthenticationSuccessEvent(this, USERNAME, AUTH_METHOD));

        AuditEvent event = getAuditEvent();
        AuditEntry entry = event.getEntry();
        assertContains(entry.getDetails(), AUTH_METHOD);
        assertEquals(USERNAME, entry.getTarget());
        assertEventCommonDetails(event, Priority.LOW);
    }
}
