/*
documentr - Edit, maintain, and present software documentation on the web.
Copyright (C) 2012-2013 Maik Schreiber
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.blizzy.documentr.page;
import static de.blizzy.documentr.TestUtil.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.reflect.Whitebox;
import org.springframework.context.MessageSource;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import de.blizzy.documentr.AbstractDocumentrTest;
import de.blizzy.documentr.Settings;
import de.blizzy.documentr.access.User;
import de.blizzy.documentr.repository.GlobalRepositoryManager;
import de.blizzy.documentr.repository.LockManager;
import de.blizzy.documentr.repository.ProjectRepositoryManagerFactory;
public class CherryPickerTest extends AbstractDocumentrTest {
private static final String PROJECT = "project"; //$NON-NLS-1$
private static final String BRANCH_1 = "branch_1"; //$NON-NLS-1$
private static final String BRANCH_2 = "branch_2"; //$NON-NLS-1$
private static final String PAGE = "page"; //$NON-NLS-1$
private static final User USER = new User("currentUser", "pw", "admin@example.com", false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final Locale LOCALE = Locale.ENGLISH;
@Rule
public TemporaryFolder tempDir = new TemporaryFolder();
@Mock
private EventBus eventBus;
@Mock
private Settings settings;
@Mock
@SuppressWarnings("unused")
private LockManager lockManager;
@Mock
private MessageSource messageSource;
private GlobalRepositoryManager globalRepoManager;
private PageStore pageStore;
private CherryPicker cherryPicker;
@InjectMocks
private ProjectRepositoryManagerFactory repoManagerFactory;
@Before
public void setUp() {
File dataDir = tempDir.getRoot();
when(settings.getDocumentrDataDir()).thenReturn(dataDir);
globalRepoManager = new GlobalRepositoryManager();
Whitebox.setInternalState(globalRepoManager, settings, repoManagerFactory, eventBus);
globalRepoManager.init();
pageStore = new PageStore();
Whitebox.setInternalState(pageStore, globalRepoManager, eventBus);
when(messageSource.getMessage(eq("sourceBranchX"), any(Object[].class), any(Locale.class))).thenReturn("THEIRS"); //$NON-NLS-1$ //$NON-NLS-2$
when(messageSource.getMessage(eq("targetBranchX"), any(Object[].class), any(Locale.class))).thenReturn("OURS"); //$NON-NLS-1$ //$NON-NLS-2$
cherryPicker = new CherryPicker();
Whitebox.setInternalState(cherryPicker, globalRepoManager, eventBus, messageSource);
}
@Test
public void cherryPickNonConflictingEdits() throws IOException, GitAPIException {
register(globalRepoManager.createProjectCentralRepository(PROJECT, USER));
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_1, null));
Page page = Page.fromText("title", "a\nb\nc\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
sleep(1000); // must wait because commit time is stored in seconds
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_2, BRANCH_1));
page = Page.fromText("title", "aaa\nb\nc\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit1 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nbbb\nc\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit2 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
Map<String, List<CommitCherryPickResult>> results = cherryPicker.cherryPick(
PROJECT, BRANCH_1, PAGE, Lists.newArrayList(commit1, commit2), Sets.newHashSet(BRANCH_2),
Collections.<CommitCherryPickConflictResolve>emptySet(), false, USER, LOCALE);
List<CommitCherryPickResult> branchResults = results.get(BRANCH_2);
CommitCherryPickResult commit1Result = branchResults.get(0);
assertEquals(commit1, commit1Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit1Result.getStatus());
assertNull(commit1Result.getConflictText());
CommitCherryPickResult commit2Result = branchResults.get(1);
assertEquals(commit2, commit2Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit2Result.getStatus());
assertNull(commit2Result.getConflictText());
page = pageStore.getPage(PROJECT, BRANCH_2, PAGE, true);
assertEquals("aaa\nbbb\nc\n", ((PageTextData) page.getData()).getText()); //$NON-NLS-1$
}
@Test
public void cherryPickConflictingEdits() throws IOException, GitAPIException {
register(globalRepoManager.createProjectCentralRepository(PROJECT, USER));
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_1, null));
Page page = Page.fromText("title", "a\nb\nc\nd\ne\nf\ng\nh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
sleep(1000); // must wait because commit time is stored in seconds
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_2, BRANCH_1));
page = Page.fromText("title", "a\nb\nc\nd\ne\nf\ng\nxxx\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_2, PAGE, page, null, USER);
page = Page.fromText("title", "aaa\nb\nc\nd\ne\nf\ng\nh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit1 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nb\nc\nd\ne\nf\ng\nhhh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit2 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nbbb\nc\nd\ne\nf\ng\nhhh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit3 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
Map<String, List<CommitCherryPickResult>> results = cherryPicker.cherryPick(
PROJECT, BRANCH_1, PAGE, Lists.newArrayList(commit1, commit2, commit3), Sets.newHashSet(BRANCH_2),
Collections.<CommitCherryPickConflictResolve>emptySet(), false, USER, LOCALE);
List<CommitCherryPickResult> branchResults = results.get(BRANCH_2);
CommitCherryPickResult commit1Result = branchResults.get(0);
assertEquals(commit1, commit1Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit1Result.getStatus());
assertNull(commit1Result.getConflictText());
CommitCherryPickResult commit2Result = branchResults.get(1);
assertEquals(commit2, commit2Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.CONFLICT, commit2Result.getStatus());
assertEquals("aaa\nb\nc\nd\ne\nf\ng\n<<<<<<< OURS\nxxx\n=======\nhhh\n>>>>>>> THEIRS\ni\n", //$NON-NLS-1$
commit2Result.getConflictText());
CommitCherryPickResult commit3Result = branchResults.get(2);
assertEquals(commit3, commit3Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.UNKNOWN, commit3Result.getStatus());
assertNull(commit3Result.getConflictText());
page = pageStore.getPage(PROJECT, BRANCH_2, PAGE, true);
assertEquals("a\nb\nc\nd\ne\nf\ng\nxxx\ni\n", ((PageTextData) page.getData()).getText()); //$NON-NLS-1$
}
@Test
public void cherryPickConflictingEditsWithConflictResolves() throws IOException, GitAPIException {
register(globalRepoManager.createProjectCentralRepository(PROJECT, USER));
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_1, null));
Page page = Page.fromText("title", "a\nb\nc\nd\ne\nf\ng\nh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
sleep(1000); // must wait because commit time is stored in seconds
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_2, BRANCH_1));
page = Page.fromText("title", "a\nb\nc\nd\ne\nf\ng\nxxx\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_2, PAGE, page, null, USER);
page = Page.fromText("title", "aaa\nb\nc\nd\ne\nf\ng\nh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit1 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nb\nc\nd\ne\nf\ng\nhhh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit2 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nbbb\nc\nd\ne\nf\ng\nhhh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit3 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
Set<CommitCherryPickConflictResolve> resolves = Sets.newHashSet(
new CommitCherryPickConflictResolve(BRANCH_2, commit2,
"<<<<<<< OURS\nxxx\n=======\nyyy\n>>>>>>> THEIRS\n")); //$NON-NLS-1$
Map<String, List<CommitCherryPickResult>> results = cherryPicker.cherryPick(
PROJECT, BRANCH_1, PAGE, Lists.newArrayList(commit1, commit2, commit3), Sets.newHashSet(BRANCH_2),
resolves, false, USER, LOCALE);
List<CommitCherryPickResult> branchResults = results.get(BRANCH_2);
CommitCherryPickResult commit1Result = branchResults.get(0);
assertEquals(commit1, commit1Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit1Result.getStatus());
assertNull(commit1Result.getConflictText());
CommitCherryPickResult commit2Result = branchResults.get(1);
assertEquals(commit2, commit2Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.CONFLICT, commit2Result.getStatus());
assertEquals("<<<<<<< OURS\nxxx\n=======\nyyy\n>>>>>>> THEIRS\n", //$NON-NLS-1$
commit2Result.getConflictText());
CommitCherryPickResult commit3Result = branchResults.get(2);
assertEquals(commit3, commit3Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.UNKNOWN, commit3Result.getStatus());
assertNull(commit3Result.getConflictText());
page = pageStore.getPage(PROJECT, BRANCH_2, PAGE, true);
assertEquals("a\nb\nc\nd\ne\nf\ng\nxxx\ni\n", ((PageTextData) page.getData()).getText()); //$NON-NLS-1$
}
@Test
public void cherryPickDryRunMustNotModifyPage() throws IOException, GitAPIException {
register(globalRepoManager.createProjectCentralRepository(PROJECT, USER));
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_1, null));
Page page = Page.fromText("title", "a\nb\nc\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_2, BRANCH_1));
page = Page.fromText("title", "aaa\nb\nc\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
cherryPicker.cherryPick(PROJECT, BRANCH_1, PAGE, Lists.newArrayList(commit), Sets.newHashSet(BRANCH_2),
Collections.<CommitCherryPickConflictResolve>emptySet(), true, USER, LOCALE);
page = pageStore.getPage(PROJECT, BRANCH_2, PAGE, true);
assertEquals("a\nb\nc\n", ((PageTextData) page.getData()).getText()); //$NON-NLS-1$
}
@Test
public void cherryPickConflictingEditsWithUnresolvedConflictResolves() throws IOException, GitAPIException {
register(globalRepoManager.createProjectCentralRepository(PROJECT, USER));
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_1, null));
Page page = Page.fromText("title", "a\nb\nc\nd\ne\nf\ng\nh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
sleep(1000); // must wait because commit time is stored in seconds
register(globalRepoManager.createProjectBranchRepository(PROJECT, BRANCH_2, BRANCH_1));
page = Page.fromText("title", "a\nb\nc\nd\ne\nf\ng\nxxx\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_2, PAGE, page, null, USER);
page = Page.fromText("title", "aaa\nb\nc\nd\ne\nf\ng\nh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit1 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nb\nc\nd\ne\nf\ng\nhhh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit2 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
sleep(1000); // must wait because commit time is stored in seconds
page = Page.fromText("title", "aaa\nbbb\nc\nd\ne\nf\ng\nhhh\ni\n"); //$NON-NLS-1$ //$NON-NLS-2$
pageStore.savePage(PROJECT, BRANCH_1, PAGE, page, null, USER);
String commit3 = pageStore.getPageMetadata(PROJECT, BRANCH_1, PAGE).getCommit();
Set<CommitCherryPickConflictResolve> resolves = Sets.newHashSet(
new CommitCherryPickConflictResolve(BRANCH_2, commit2, "aaa\nb\nc\nd\ne\nf\ng\nhhh xxx\ni\n")); //$NON-NLS-1$
Map<String, List<CommitCherryPickResult>> results = cherryPicker.cherryPick(
PROJECT, BRANCH_1, PAGE, Lists.newArrayList(commit1, commit2, commit3), Sets.newHashSet(BRANCH_2),
resolves, false, USER, LOCALE);
List<CommitCherryPickResult> branchResults = results.get(BRANCH_2);
CommitCherryPickResult commit1Result = branchResults.get(0);
assertEquals(commit1, commit1Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit1Result.getStatus());
assertNull(commit1Result.getConflictText());
CommitCherryPickResult commit2Result = branchResults.get(1);
assertEquals(commit2, commit2Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit2Result.getStatus());
assertNull(commit2Result.getConflictText());
CommitCherryPickResult commit3Result = branchResults.get(2);
assertEquals(commit3, commit3Result.getPageVersion().getCommitName());
assertSame(CommitCherryPickResult.Status.OK, commit3Result.getStatus());
assertNull(commit3Result.getConflictText());
page = pageStore.getPage(PROJECT, BRANCH_2, PAGE, true);
assertEquals("aaa\nbbb\nc\nd\ne\nf\ng\nhhh xxx\ni\n", ((PageTextData) page.getData()).getText()); //$NON-NLS-1$
}
@Test
public void getCommitsList() throws IOException {
pageStore = mock(PageStore.class);
Whitebox.setInternalState(cherryPicker, pageStore);
@SuppressWarnings("nls")
List<PageVersion> versions = Lists.newArrayList(
new PageVersion("commit5", "user", new Date()),
new PageVersion("commit4", "user", new Date()),
new PageVersion("commit3", "user", new Date()),
new PageVersion("commit2", "user", new Date()),
new PageVersion("commit1", "user", new Date())
);
when(pageStore.listPageVersions(PROJECT, BRANCH_1, PAGE)).thenReturn(versions);
List<String> result = cherryPicker.getCommitsList(PROJECT, BRANCH_1, PAGE, "commit2", "commit4"); //$NON-NLS-1$ //$NON-NLS-2$
List<String> commits = Lists.newArrayList("commit3", "commit4"); //$NON-NLS-1$ //$NON-NLS-2$
assertEquals(commits, result);
}
}