package com.atlassian.bitbucket.mesh.git.gc;

import com.atlassian.bitbucket.mesh.git.GitRepositories;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.test.annotation.DirtiesRepo;
import com.atlassian.bitbucket.mesh.test.annotation.Repo;
import org.junit.Test;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import static org.mockito.Mockito.*;

public class DefaultGarbageCollectionManagerForBitbucketRepositoryTest extends BaseGarbageCollectionManagerWiredTest {

    @Repo(value = GitRepositories.GARBAGE, type = Repo.Type.BITBUCKET_SERVER)
    private Repository bbsRepository;

    @DirtiesRepo
    @Test
    public void testPackRefsRunsRegardlessEvenIfRepackIsUnnecessary() {
        collectGarbage(repository);

        assertFalse(hasRepackRun(repository));
        assertTrue(hasPackRefsRun(repository));

        maybeVerifyCommitGraph(repository, false);
    }

    //Repack is only run for Bitbucket Server repositories. For managed repositories, repack is only run when
    //garbage collection runs for the shared-objects repository (after it is vacuumed). For this reason, tests
    //for repack or interaction with repack are only performed for Bitbucket Server repositories.

    @DirtiesRepo
    @Test
    public void testPackRefsRunsRegardlessOfRecentRepack() throws IOException {
        mockRepackRun(repository, System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(1L));

        garbageCollectionManager.collectGarbage(new GarbageCollectionParameters.Builder(repository)
                .added(1)
                .build()
        );

        verify(executorService, atLeastOnce())
                .schedule(any(DefaultGarbageCollectionManager.GcBootstrapper.class), anyLong(), any());
    }

    @DirtiesRepo
    @Test
    public void testUnreachableObjectHandlingWhenPruningDisabled() throws IOException {
        // set up the repository with all kinds of artifacts from our fork gc strategy
        disablePrune(repository);
        createLooseObjects(repository);

        // run a gc to create a loose pack
        collectGarbage(repository);

        //verify that GC has created one pack and that there are no loose objects
        assertEquals("All objects should have been written in a single pack", 1, countPackFiles(repository));
        assertEquals("Unreachable objects should have also been packed", 0, countLooseObjects(repository));
    }

    @Override
    protected Repository getRepositoryThatShouldBeRepacked() {
        return bbsRepository;
    }

    @Override
    protected Repository getRepositoryUnderTest() {
        return bbsRepository;
    }
}
