/*******************************************************************************
* Copyright (C) 2010-2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.egit.ui.view.synchronize;
import static org.eclipse.egit.ui.internal.UIText.CommitDialog_Commit;
import static org.eclipse.egit.ui.internal.UIText.CommitDialog_CommitChanges;
import static org.eclipse.egit.ui.internal.UIText.CommitDialog_SelectAll;
import static org.eclipse.egit.ui.test.ContextMenuHelper.clickContextMenu;
import static org.eclipse.egit.ui.test.TestUtil.waitUntilTreeHasNodeContainsText;
import static org.eclipse.jface.dialogs.MessageDialogWithToggle.NEVER;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.eclipse.team.internal.ui.IPreferenceIds.SYNCHRONIZING_COMPLETE_PERSPECTIVE;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.op.CommitOperation;
import org.eclipse.egit.core.op.ConnectProviderOperation;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.common.CompareEditorTester;
import org.eclipse.egit.ui.common.LocalRepositoryTestCase;
import org.eclipse.egit.ui.internal.synchronize.GitModelSynchronize;
import org.eclipse.egit.ui.test.JobJoiner;
import org.eclipse.egit.ui.test.TestUtil;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor;
import org.eclipse.swtbot.swt.finder.SWTBot;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.ui.TeamUI;
import org.eclipse.team.ui.mapping.ITeamContentProviderDescriptor;
import org.eclipse.team.ui.mapping.ITeamContentProviderManager;
import org.eclipse.team.ui.synchronize.ISynchronizeManager;
import org.eclipse.team.ui.synchronize.ISynchronizeView;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
@SuppressWarnings("restriction")
public abstract class AbstractSynchronizeViewTest extends
LocalRepositoryTestCase {
protected static final String INITIAL_TAG = R_TAGS + "initial-tag";
protected static final String TEST_COMMIT_MSG = "test commit";
protected static final String EMPTY_PROJECT = "EmptyProject";
protected static final String EMPTY_REPOSITORY = "EmptyRepository";
protected File repositoryFile;
protected File childRepositoryFile;
@Before
public void setupViews() {
Activator.getDefault().getPreferenceStore()
.setValue(UIPreferences.ALWAYS_USE_STAGING_VIEW, false);
TestUtil.showExplorerView();
}
@After
public void closeSynchronizeView() {
Activator.getDefault().getPreferenceStore()
.setValue(UIPreferences.ALWAYS_USE_STAGING_VIEW, true);
TestUtil.hideView(ISynchronizeView.VIEW_ID);
}
@After
public void deleteEmptyProject() throws Exception {
IProject prj = ResourcesPlugin.getWorkspace().getRoot()
.getProject(EMPTY_PROJECT);
if (prj.exists()) {
prj.delete(false, false, null);
TestUtil.waitForJobs(50, 5000);
}
}
@Before
public void setupRepository() throws Exception {
repositoryFile = createProjectAndCommitToRepository();
createAndCommitDotGitignore();
childRepositoryFile = createChildRepository(repositoryFile);
createTag(INITIAL_TAG);
Activator.getDefault().getRepositoryUtil()
.addConfiguredRepository(repositoryFile);
}
@BeforeClass
public static void setupEnvironment() throws Exception {
// disable perspective synchronize selection
TeamUIPlugin.getPlugin().getPreferenceStore().setValue(
SYNCHRONIZING_COMPLETE_PERSPECTIVE, NEVER);
Activator.getDefault().getPreferenceStore()
.setValue(UIPreferences.SYNC_VIEW_FETCH_BEFORE_LAUNCH, false);
TestUtil.showExplorerView();
}
protected void changeFilesInProject() throws Exception {
SWTBot packageExlBot = bot.viewById(JavaUI.ID_PACKAGES).bot();
SWTBotTreeItem coreTreeItem = selectProject(PROJ1, packageExlBot.tree());
SWTBotTreeItem rootNode = TestUtil.expandAndWait(coreTreeItem);
rootNode = TestUtil.expandAndWait(rootNode.getNode(0)).select();
rootNode.getNode(0).select().doubleClick();
SWTBotEditor corePomEditor = bot.editorByTitle(FILE1);
corePomEditor.toTextEditor()
.insertText("<!-- EGit jUnit test case -->");
corePomEditor.saveAndClose();
rootNode.getNode(1).select().doubleClick();
SWTBotEditor uiPomEditor = bot.editorByTitle(FILE2);
uiPomEditor.toTextEditor().insertText("<!-- EGit jUnit test case -->");
uiPomEditor.saveAndClose();
coreTreeItem.collapse();
}
protected void createTag(String tagName)
throws Exception {
try (Git git = new Git(lookupRepository(repositoryFile))) {
git.tag().setName(tagName).setMessage(tagName).call();
}
}
protected void makeChangesAndCommit(String projectName) throws Exception {
changeFilesInProject();
commit(projectName);
}
protected void deleteFileAndCommit(String projectName) throws Exception {
ResourcesPlugin.getWorkspace().getRoot().getProject(PROJ1)
.getFile(new Path("folder/test.txt")).delete(true, null);
commit(projectName);
}
protected void launchSynchronization(String srcRef, String dstRef,
boolean includeLocal) throws IOException {
launchSynchronization(PROJ1, srcRef, dstRef, includeLocal);
}
protected void launchSynchronization(String projectName, String srcRef,
String dstRef, boolean includeLocal) throws IOException {
IProject project = ResourcesPlugin.getWorkspace().getRoot()
.getProject(projectName);
RepositoryMapping mapping = assertConnected(project);
Repository repo = mapping.getRepository();
GitSynchronizeData data = new GitSynchronizeData(repo, srcRef, dstRef,
includeLocal);
JobJoiner jobJoiner = JobJoiner.startListening(
ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION, 60,
TimeUnit.SECONDS);
GitModelSynchronize.launch(data, new IResource[] { project });
jobJoiner.join();
}
protected void setEnabledModelProvider(String modelProviderId) {
ITeamContentProviderManager contentProviderManager = TeamUI.getTeamContentProviderManager();
ITeamContentProviderDescriptor descriptor = contentProviderManager.getDescriptor(modelProviderId);
contentProviderManager.setEnabledDescriptors(new ITeamContentProviderDescriptor[] { descriptor });
}
// based on LocalRepositoryTestCase#createProjectAndCommitToRepository(String)
protected void createEmptyRepository() throws Exception {
File gitDir = new File(new File(getTestDirectory(), EMPTY_REPOSITORY),
Constants.DOT_GIT);
Repository myRepository = FileRepositoryBuilder.create(gitDir);
myRepository.create();
// we need to commit into master first
IProject firstProject = ResourcesPlugin.getWorkspace().getRoot()
.getProject(EMPTY_PROJECT);
if (firstProject.exists()) {
firstProject.delete(true, null);
TestUtil.waitForJobs(100, 5000);
}
IProjectDescription desc = ResourcesPlugin.getWorkspace()
.newProjectDescription(EMPTY_PROJECT);
desc.setLocation(new Path(new File(myRepository.getWorkTree(),
EMPTY_PROJECT).getPath()));
firstProject.create(desc, null);
firstProject.open(null);
assertTrue("Project is not accessible: " + firstProject,
firstProject.isAccessible());
IFolder folder = firstProject.getFolder(FOLDER);
folder.create(false, true, null);
IFile textFile = folder.getFile(FILE1);
textFile.create(new ByteArrayInputStream("Hello, world"
.getBytes(firstProject.getDefaultCharset())), false, null);
IFile textFile2 = folder.getFile(FILE2);
textFile2.create(new ByteArrayInputStream("Some more content"
.getBytes(firstProject.getDefaultCharset())), false, null);
TestUtil.waitForJobs(50, 5000);
try {
new ConnectProviderOperation(firstProject, gitDir).execute(null);
} catch (Exception e) {
Activator.logError("Failed to connect project to repository", e);
}
assertConnected(firstProject);
}
protected SWTBotTreeItem waitForNodeWithText(SWTBotTree tree, String name) {
waitUntilTreeHasNodeContainsText(bot, tree, name, 10000);
return getTreeItemContainingText(tree.getAllItems(), name).expand();
}
protected SWTBotTreeItem waitForNodeWithText(SWTBotTreeItem tree,
String name) {
waitUntilTreeHasNodeContainsText(bot, tree, name, 15000);
return getTreeItemContainingText(tree.getItems(), name).expand();
}
private static void createAndCommitDotGitignore() throws CoreException,
UnsupportedEncodingException {
IProject secondPoject = ResourcesPlugin.getWorkspace().getRoot()
.getProject(PROJ2);
IFile gitignore = secondPoject.getFile(".gitignore");
gitignore.create(
new ByteArrayInputStream("/.project\n".getBytes(secondPoject
.getDefaultCharset())), false, null);
IFile[] commitables = new IFile[] { gitignore };
ArrayList<IFile> untracked = new ArrayList<IFile>();
untracked.addAll(Arrays.asList(commitables));
CommitOperation op = new CommitOperation(commitables,
untracked, TestUtil.TESTAUTHOR, TestUtil.TESTCOMMITTER,
"Add .gitignore file");
op.execute(null);
}
protected void commit(String projectName) throws InterruptedException {
showDialog(projectName, "Team", "Commit...");
SWTBot shellBot = bot.shell(CommitDialog_CommitChanges).bot();
shellBot.styledText(0).setText(TEST_COMMIT_MSG);
shellBot.toolbarButtonWithTooltip(CommitDialog_SelectAll).click();
shellBot.button(CommitDialog_Commit).click();
TestUtil.joinJobs(JobFamilies.COMMIT);
}
protected CompareEditorTester getCompareEditor(SWTBotTreeItem projectNode,
final String fileName) {
SWTBotTreeItem folderNode = waitForNodeWithText(projectNode, FOLDER);
waitForNodeWithText(folderNode, fileName).doubleClick();
return CompareEditorTester.forTitleContaining(fileName);
}
private static void showDialog(String projectName, String... cmd) {
SWTBotTree tree = TestUtil.getExplorerTree();
// EGit decorates the project node shown in the package explorer. The
// '>' decorator indicates that there are uncommitted changes present in
// the project. Also the repository and branch name are added as a
// suffix ('[<repo name> <branch name>]' suffix). To bypass this
// decoration we use here this loop.
selectProject(projectName, tree);
clickContextMenu(tree, cmd);
}
private static SWTBotTreeItem selectProject(String projectName,
SWTBotTree tree) {
for (SWTBotTreeItem item : tree.getAllItems())
if (item.getText().contains(projectName)) {
item.select();
return item;
}
throw new RuntimeException("Project with name " + projectName +
" was not found in given tree");
}
private SWTBotTreeItem getTreeItemContainingText(SWTBotTreeItem[] items,
String text) {
return TestUtil.getNode(items, text);
}
}