package com.atlassian.bitbucket.internal.mirroring.mirror.scm.check;

import com.atlassian.bitbucket.i18n.SimpleI18nService;
import com.atlassian.bitbucket.project.Project;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.ScmRequest;
import com.atlassian.bitbucket.scm.ScmRequestCheck;
import com.atlassian.bitbucket.server.ApplicationMode;
import com.atlassian.bitbucket.server.ApplicationPropertiesService;
import com.atlassian.event.api.EventPublisher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ReadOnlyRequestCheckTest {
    @Mock
    private ApplicationPropertiesService appPropsService;
    private ScmRequestCheck check;
    @Mock
    private EventPublisher eventPublisher;
    @Spy
    private SimpleI18nService i18nService;
    @Mock
    private ScmRequest request;
    @Mock
    private Repository repository;

    @Before
    public void setUp() throws Exception {
        when(request.getRepository()).thenReturn(repository);
        when(repository.getProject()).thenReturn(mock(Project.class));
    }

    @Test
    public void testCheckSucceedsIfReadRequestWhenNotMirror() throws Exception {
        when(request.isWrite()).thenReturn(false);

        check = newCheck();

        assertTrue(check.check(request));

        verify(eventPublisher, never()).publish(any());
    }

    @Test
    public void testCheckSucceedsIfWriteRequestWhenNotMirror() throws Exception {
        when(request.isWrite()).thenReturn(true);

        check = newCheck(ApplicationMode.DEFAULT);

        assertTrue(check.check(request));

        verify(eventPublisher, never()).publish(any());
    }

    @Test
    public void testCheckSucceedsIfNotWriteRequestWhenMirror() throws Exception {
        when(request.isWrite()).thenReturn(true);

        check = newCheck();

        assertFalse(check.check(request));

        verify(request).sendError(anyString(), anyString());
        verify(eventPublisher).publish(isA(ReadOnlyMirrorPushAnalyticsEvent.class));
    }

    @Test
    public void testCheckFailsIfWriteRequestWhenMirror() throws Exception {
        when(request.isWrite()).thenReturn(true);

        check = newCheck();

        assertFalse(check.check(request));

        verify(request).sendError(anyString(), anyString());
        verify(eventPublisher).publish(isA(ReadOnlyMirrorPushAnalyticsEvent.class));
    }

    private ReadOnlyRequestCheck newCheck() {
        return newCheck(ApplicationMode.MIRROR);
    }

    private ReadOnlyRequestCheck newCheck(ApplicationMode mode) {
        return new ReadOnlyRequestCheck(eventPublisher, i18nService, () -> mode);
    }
}