blob: 05f8367ed5843b71cb7625a559aa11aeb85a0cca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2013 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Mathias Kinzler (SAP AG) - initial implementation
*******************************************************************************/
package org.eclipse.egit.ui.common;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
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.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.GitCorePreferences;
import org.eclipse.egit.core.GitProvider;
import org.eclipse.egit.core.JobFamilies;
import org.eclipse.egit.core.RepositoryCache;
import org.eclipse.egit.core.RepositoryUtil;
import org.eclipse.egit.core.internal.indexdiff.IndexDiffCache;
import org.eclipse.egit.core.internal.util.ResourceUtil;
import org.eclipse.egit.core.op.AddToIndexOperation;
import org.eclipse.egit.core.op.CloneOperation;
import org.eclipse.egit.core.op.CommitOperation;
import org.eclipse.egit.core.op.ConnectProviderOperation;
import org.eclipse.egit.core.op.ListRemoteOperation;
import org.eclipse.egit.core.project.GitProjectData;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.core.test.TestUtils;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.dialogs.CompareTreeView;
import org.eclipse.egit.ui.internal.push.PushOperationUI;
import org.eclipse.egit.ui.internal.rebase.RebaseInteractiveView;
import org.eclipse.egit.ui.internal.reflog.ReflogView;
import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.egit.ui.internal.staging.StagingView;
import org.eclipse.egit.ui.test.ContextMenuHelper;
import org.eclipse.egit.ui.test.Eclipse;
import org.eclipse.egit.ui.test.TestUtil;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.SystemReader;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.ui.history.IHistoryView;
import org.eclipse.team.ui.synchronize.ISynchronizeView;
import org.eclipse.ui.PlatformUI;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.rules.TestName;
/**
* Base class for testing with local (file-system based) repositories
* <p>
* This supports single repository scenarios as well as "remote" scenarios with
* two local repositories that are interconnected with each other via the
* "origin" configuration.
* <p>
* The repositories are created under a directory named "LocalRepositoriesTests"
* under the user home directory and everything is deleted recursively in
* {@link #afterClassBase()}.
* <p>
* {@link #createProjectAndCommitToRepository()} creates a couple of projects
* and adds them to a local repository named {@link #REPO1}.
* <p>
* {@link #createRemoteRepository(File)} creates a bare repository based on the
* File of another repository. The original repository will be configured with
* three remote specifications that can be used to push to the bare repository
* with slightly different set-ups (combinations of urls and specs): fetch,
* push, both, and mixed
* <p>
* A typical code sequence for setting up these two repositories could look
* like:
*
* <pre>
* private File localRepo;
* private File remoteRepo;
* ...
* {@literal @}Before
* public void initRepos() throws Exception {
* localRepo = repositoryFile = createProjectAndCommitToRepository();
* remtoeRepo =remoteRepositoryFile = createRemoteRepository(repositoryFile);
* }
* </pre>
* <p>
* {@link #createChildRepository(File)} creates a "child" repository based on
* the File another repository; the child will be cloned from the original
* repository and a "origin" remote spec will be set-up automatically
*/
public abstract class LocalRepositoryTestCase extends EGitTestCase {
private static int testMethodNumber = 0;
// the temporary directory
private File testDirectory;
protected static final String REPO1 = "FirstRepository";
protected static final String REPO2 = "RemoteRepository";
protected static final String REMOTE_REPO_SIMPLE = "SimpleRemoteRepository";
protected static final String CHILDREPO = "ChildRepository";
/** A general project containing FOLDER containing FILE1 and FILE2 */
protected static final String PROJ1 = "GeneralProject";
/** A folder obtained by checking in a project without .project */
protected static final String PROJ2 = "ProjectWithoutDotProject";
protected static final String FOLDER = "folder";
protected static final String FILE1 = "test.txt";
protected static final String FILE1_PATH = PROJ1 + "/" + FOLDER + "/"
+ FILE1;
protected static final String FILE2 = "test2.txt";
protected final static TestUtils testUtils = new TestUtils();
private static final String[] VIEWS_TO_CLOSE = { //
RebaseInteractiveView.VIEW_ID, //
ISynchronizeView.VIEW_ID, //
IHistoryView.VIEW_ID, //
CompareTreeView.ID, //
ReflogView.VIEW_ID, //
StagingView.VIEW_ID, //
RepositoriesView.VIEW_ID, //
"org.eclipse.search.ui.views.SearchView", //
"org.eclipse.ui.views.PropertySheet"
};
@Rule
public TestName testName = new TestName();
public File getTestDirectory() {
return testDirectory;
}
protected static void closeGitViews() {
for (String viewId : VIEWS_TO_CLOSE) {
TestUtil.hideView(viewId);
}
}
@Before
public void initNewTestDirectory() throws Exception {
testMethodNumber++;
// create standalone temporary directory
testDirectory = testUtils.createTempDir("LocalRepositoriesTests"
+ testMethodNumber + '_' + testName.getMethodName());
if (testDirectory.exists())
FileUtils.delete(testDirectory, FileUtils.RECURSIVE
| FileUtils.RETRY);
if (!testDirectory.exists())
FileUtils.mkdir(testDirectory, true);
// we don't want to clone into <user_home> but into our test directory
File repoRoot = new File(testDirectory, "RepositoryRoot");
if (!repoRoot.exists())
FileUtils.mkdir(repoRoot, true);
// make sure the default directory for Repos is not the user home
IEclipsePreferences p = InstanceScope.INSTANCE
.getNode(Activator.getPluginId());
p.put(GitCorePreferences.core_defaultRepositoryDir, repoRoot.getPath());
File configFile = File.createTempFile("gitconfigtest", "config");
MockSystemReader mockSystemReader = new MockSystemReader() {
@Override
public FileBasedConfig openUserConfig(Config parent, FS fs) {
return new FileBasedConfig(parent, configFile, fs);
}
};
// unset git user properties
mockSystemReader.setProperty(Constants.GIT_AUTHOR_NAME_KEY, null);
mockSystemReader.setProperty(Constants.GIT_AUTHOR_EMAIL_KEY, null);
mockSystemReader.setProperty(Constants.GIT_COMMITTER_NAME_KEY, null);
mockSystemReader.setProperty(Constants.GIT_COMMITTER_EMAIL_KEY, null);
configFile.deleteOnExit();
SystemReader.setInstance(mockSystemReader);
mockSystemReader.setProperty(Constants.GIT_CEILING_DIRECTORIES_KEY,
ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile()
.getParentFile().getAbsoluteFile().toString());
FileBasedConfig userConfig = mockSystemReader.openUserConfig(null,
FS.DETECTED);
// We have to set autoDetach to false for tests, because tests expect to
// be able to clean up by recursively removing the repository, and
// background GC might be in the middle of writing or deleting files,
// which would disrupt this.
userConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTODETACH, false);
userConfig.save();
}
@After
public void resetWorkspace() throws Exception {
TestUtil.processUIEvents();
// close all editors/dialogs
new Eclipse().reset();
clearAllConfiguredRepositories();
closeGitViews();
TestUtil.processUIEvents();
// cleanup
for (IProject project : ResourcesPlugin.getWorkspace().getRoot()
.getProjects()) {
project.delete(false, false, null);
}
shutDownRepositories();
TestUtil.waitForJobs(50, 5000);
}
@BeforeClass
public static void beforeClassBase() throws Exception {
FS.FileStoreAttributes.setBackground(false);
// suppress auto-ignoring and auto-sharing to avoid interference
IEclipsePreferences corePrefs = InstanceScope.INSTANCE
.getNode(org.eclipse.egit.core.Activator.getPluginId());
corePrefs.putBoolean(
GitCorePreferences.core_autoIgnoreDerivedResources, false);
corePrefs.putBoolean(GitCorePreferences.core_autoShareProjects, false);
IPreferenceStore uiPrefs = org.eclipse.egit.ui.Activator.getDefault()
.getPreferenceStore();
// suppress the configuration dialog
uiPrefs.setValue(UIPreferences.SHOW_INITIAL_CONFIG_DIALOG, false);
// suppress the detached head warning dialog
uiPrefs.setValue(UIPreferences.SHOW_DETACHED_HEAD_WARNING, false);
// suppress checking for external changes to git repositories
uiPrefs.setValue(UIPreferences.REFRESH_INDEX_INTERVAL, 0);
closeGitViews();
}
@AfterClass
public static void afterClassBase() throws Exception {
File tempDir = testUtils.getBaseTempDir();
if (tempDir.toString().startsWith("/home") && tempDir.exists()) {
// see bug 440182: if test has left opened file streams on NFS
// mounted directories "delete" will fail because the directory
// would contain "stolen NFS file handles" (something like .nfs*
// files) so the "first round" of delete can ignore failures.
FileUtils.delete(tempDir, FileUtils.IGNORE_ERRORS
| FileUtils.RECURSIVE | FileUtils.RETRY);
}
testUtils.deleteTempDirs();
}
@SuppressWarnings("deprecation")
protected void clearAllConfiguredRepositories() throws Exception {
IEclipsePreferences prefs = Activator.getDefault().getRepositoryUtil()
.getPreferences();
synchronized (prefs) {
prefs.put(RepositoryUtil.PREFS_DIRECTORIES, "");
prefs.put(RepositoryUtil.PREFS_DIRECTORIES_REL, "");
prefs.flush();
}
}
protected static void shutDownRepositories() throws Exception {
RepositoryCache cache = Activator.getDefault().getRepositoryCache();
for (Repository repository : cache.getAllRepositories()) {
repository.close();
}
cache.clear();
}
protected static void deleteAllProjects() throws Exception {
for (IProject prj : ResourcesPlugin.getWorkspace().getRoot()
.getProjects()) {
if (prj.getName().equals(PROJ1)) {
prj.delete(false, false, null);
} else if (prj.getName().equals(PROJ2)) {
// delete the .project on disk
File dotProject = prj.getLocation().append(".project").toFile();
prj.delete(false, false, null);
FileUtils.delete(dotProject, FileUtils.RETRY);
}
}
TestUtil.waitForJobs(50, 5000);
}
protected File createProjectAndCommitToRepository() throws Exception {
return createProjectAndCommitToRepository(REPO1);
}
protected File createProjectAndCommitToRepository(String repoName)
throws Exception {
return createProjectAndCommitToRepository(repoName, PROJ1, PROJ2);
}
protected File createProjectAndCommitToRepository(String repoName,
String projectName) throws Exception {
return createProjectAndCommitToRepository(repoName, projectName, null);
}
protected File createProjectAndCommitToRepository(String repoName,
String project1Name, String project2Name) throws Exception {
Repository myRepository = createLocalTestRepository(repoName);
File gitDir = myRepository.getDirectory();
// we need to commit into master first
IProject firstProject = createStandardTestProjectInRepository(
myRepository, project1Name);
try {
new ConnectProviderOperation(firstProject, gitDir).execute(null);
} catch (Exception e) {
Activator.logError("Failed to connect project to repository", e);
}
assertConnected(firstProject);
IProject secondProject = null;
if (project2Name != null) {
secondProject = createStandardTestProjectInRepository(myRepository,
project2Name);
// TODO we should be able to hide the .project
// IFile gitignore = secondPoject.getFile(".gitignore");
// gitignore.create(new ByteArrayInputStream("/.project\n"
// .getBytes(firstProject.getDefaultCharset())), false, null);
try {
new ConnectProviderOperation(secondProject, gitDir)
.execute(null);
} catch (Exception e) {
Activator.logError("Failed to connect project to repository",
e);
}
assertConnected(secondProject);
}
IFile dotProject = firstProject.getFile(".project");
assertTrue(".project is not accessible: " + dotProject,
dotProject.isAccessible());
IFolder folder = firstProject.getFolder(FOLDER);
IFile textFile = folder.getFile(FILE1);
IFile textFile2 = folder.getFile(FILE2);
IFile[] committableFiles = null;
if (secondProject != null) {
folder = secondProject.getFolder(FOLDER);
IFile secondtextFile = folder.getFile(FILE1);
IFile secondtextFile2 = folder.getFile(FILE2);
committableFiles = new IFile[] { dotProject, textFile, textFile2,
secondtextFile, secondtextFile2 };
} else {
committableFiles = new IFile[] { dotProject, textFile, textFile2 };
}
ArrayList<IFile> untracked = new ArrayList<>();
untracked.addAll(Arrays.asList(committableFiles));
// commit to stable
CommitOperation op = new CommitOperation(committableFiles,
untracked, TestUtil.TESTAUTHOR, TestUtil.TESTCOMMITTER,
"Initial commit");
op.execute(null);
// now create a stable branch (from master)
createStableBranch(myRepository);
// and check in some stuff into master again
String newContent = "Touched at " + System.currentTimeMillis();
IFile file = touch(firstProject.getName(), FOLDER + '/' + FILE1,
newContent);
addAndCommit(file, newContent);
// Make sure cache entry is already listening for changes
IndexDiffCache cache = Activator.getDefault().getIndexDiffCache();
cache.getIndexDiffCacheEntry(lookupRepository(gitDir));
return gitDir;
}
protected Repository createLocalTestRepository(String repoName)
throws IOException {
File gitDir = new File(new File(testDirectory, repoName),
Constants.DOT_GIT);
Repository myRepository = new RepositoryBuilder().setGitDir(gitDir)
.build();
myRepository.create();
return myRepository;
}
protected IProject createStandardTestProjectInRepository(
Repository repository, String name) throws Exception {
IProject project = ResourcesPlugin.getWorkspace().getRoot()
.getProject(name);
if (project.exists()) {
project.delete(true, null);
TestUtil.waitForJobs(100, 5000);
}
IProjectDescription desc = ResourcesPlugin.getWorkspace()
.newProjectDescription(name);
desc.setLocation(
new Path(new File(repository.getWorkTree(), name).getPath()));
project.create(desc, null);
project.open(null);
TestUtil.waitForJobs(50, 5000);
assertTrue("Project is not accessible: " + project,
project.isAccessible());
IFolder folder = project.getFolder(FOLDER);
folder.create(false, true, null);
IFile textFile = folder.getFile(FILE1);
textFile.create(
new ByteArrayInputStream(
"Hello, world".getBytes(project.getDefaultCharset())),
false, null);
IFile textFile2 = folder.getFile(FILE2);
textFile2.create(new ByteArrayInputStream(
"Some more content".getBytes(project.getDefaultCharset())),
false, null);
return project;
}
protected RepositoryMapping assertConnected(IProject project) {
RepositoryProvider provider = RepositoryProvider.getProvider(project,
GitProvider.ID);
if (provider == null) {
TestUtil.waitForJobs(5000, 10000);
assertTrue("Project not shared with git: " + project,
ResourceUtil.isSharedWithGit(project));
TestUtil.waitForJobs(1000, 10000);
provider = RepositoryProvider.getProvider(project);
}
assertTrue("Project is not accessible: " + project,
project.isAccessible());
assertNotNull("GitProvider not mapped to: " + project, provider);
GitProjectData data = ((GitProvider) provider).getData();
if (data == null) {
TestUtil.waitForJobs(100, 5000);
data = ((GitProvider) provider).getData();
}
assertNotNull("GitProjectData is null for: " + project, data);
RepositoryMapping mapping = data.getRepositoryMapping(project);
if (mapping == null) {
TestUtil.waitForJobs(100, 5000);
mapping = data.getRepositoryMapping(project);
}
assertNotNull("RepositoryMapping is null for: " + project, mapping);
return mapping;
}
protected File createSimpleRemoteRepository(File repositoryDir)
throws Exception {
Repository myRepository = lookupRepository(repositoryDir);
File gitDir = new File(testDirectory, REMOTE_REPO_SIMPLE);
Repository myRemoteRepository = FileRepositoryBuilder.create(gitDir);
myRemoteRepository.create(true);
// double-check that this is bare
assertTrue(myRemoteRepository.isBare());
// now we configure the remote
myRepository.getConfig().setString("remote", "origin", "url",
"file://" + myRemoteRepository.getDirectory().getPath());
myRepository.getConfig().setString("remote", "origin", "fetch",
"+refs/heads/*:refs/remotes/origin/*");
myRepository.getConfig().save();
// and push
PushOperationUI pa = new PushOperationUI(myRepository, "origin", false);
pa.execute(null);
return myRemoteRepository.getDirectory();
}
protected File createRemoteRepository(File repositoryDir)
throws Exception {
Repository myRepository = lookupRepository(repositoryDir);
File gitDir = new File(testDirectory, REPO2);
Repository myRemoteRepository = FileRepositoryBuilder.create(gitDir);
myRemoteRepository.create(true);
// double-check that this is bare
assertTrue(myRemoteRepository.isBare());
createStableBranch(myRepository);
// now we configure a pure push destination
myRepository.getConfig().setString("remote", "push", "pushurl",
"file://" + myRemoteRepository.getDirectory().getPath());
myRepository.getConfig().setString("remote", "push", "push",
"+refs/heads/*:refs/heads/*");
// and a pure fetch destination
myRepository.getConfig().setString("remote", "fetch", "url",
"file://" + myRemoteRepository.getDirectory().getPath());
myRepository.getConfig().setString("remote", "fetch", "fetch",
"+refs/heads/*:refs/heads/*");
// a destination with both fetch and push urls and specs
myRepository.getConfig().setString("remote", "both", "pushurl",
"file://" + myRemoteRepository.getDirectory().getPath());
myRepository.getConfig().setString("remote", "both", "push",
"+refs/heads/*:refs/heads/*");
myRepository.getConfig().setString("remote", "both", "url",
"file://" + myRemoteRepository.getDirectory().getPath());
myRepository.getConfig().setString("remote", "both", "fetch",
"+refs/heads/*:refs/heads/*");
// a destination with only a fetch url and push and fetch specs
myRepository.getConfig().setString("remote", "mixed", "push",
"+refs/heads/*:refs/heads/*");
myRepository.getConfig().setString("remote", "mixed", "url",
"file://" + myRemoteRepository.getDirectory().getPath());
myRepository.getConfig().setString("remote", "mixed", "fetch",
"+refs/heads/*:refs/heads/*");
myRepository.getConfig().save();
// and push
PushOperationUI pa = new PushOperationUI(myRepository, "push", false);
pa.execute(null);
try {
// delete the stable branch again
RefUpdate op = myRepository.updateRef("refs/heads/stable");
op.setRefLogMessage("branch deleted", //$NON-NLS-1$
false);
// we set the force update in order
// to avoid having this rejected
// due to minor issues
op.setForceUpdate(true);
op.delete();
} catch (IOException ioe) {
throw new InvocationTargetException(ioe);
}
return myRemoteRepository.getDirectory();
}
protected File createChildRepository(File repositoryDir)
throws Exception {
Repository myRepository = lookupRepository(repositoryDir);
URIish uri = new URIish("file://" + myRepository.getDirectory());
File workdir = new File(testDirectory, CHILDREPO);
CloneOperation clop = new CloneOperation(uri, true, null, workdir,
"refs/heads/master", "origin", 0);
clop.run(null);
return new File(workdir, Constants.DOT_GIT);
}
protected static void createStableBranch(Repository myRepository)
throws IOException {
// let's create a stable branch temporarily so
// that we push two branches to remote
String newRefName = "refs/heads/stable";
createBranch(myRepository, newRefName);
}
protected static void createBranch(Repository myRepository,
String newRefName) throws IOException {
RefUpdate updateRef = myRepository.updateRef(newRefName);
Ref sourceBranch = myRepository.exactRef("refs/heads/master");
ObjectId startAt = sourceBranch.getObjectId();
String startBranch = Repository.shortenRefName(sourceBranch.getName());
updateRef.setNewObjectId(startAt);
updateRef
.setRefLogMessage("branch: Created from " + startBranch, false); //$NON-NLS-1$
updateRef.update();
TestUtil.waitForJobs(50, 5000);
}
protected void assertClickOpens(SWTBotTree tree, String menu, String window) {
ContextMenuHelper.clickContextMenu(tree, menu);
SWTBotShell shell = bot.shell(window);
shell.activate();
shell.bot().button(IDialogConstants.CANCEL_LABEL).click();
shell.close();
}
/**
* This method should only be used in exceptional cases.
* Try to avoid using it e.g. by joining execution jobs
* instead of waiting a given amount of time {@link TestUtil#joinJobs(Object)}
* @throws InterruptedException
*/
protected static void waitInUI() throws InterruptedException {
TestUtil.processUIEvents(1000);
}
protected void shareProjects(File repositoryDir) throws Exception {
Repository myRepository = lookupRepository(repositoryDir);
FilenameFilter projectFilter = (dir, name) -> name.equals(".project");
for (File file : myRepository.getWorkTree().listFiles()) {
if (file.isDirectory()) {
if (file.list(projectFilter).length > 0) {
IProjectDescription desc = ResourcesPlugin.getWorkspace()
.newProjectDescription(file.getName());
desc.setLocation(new Path(file.getPath()));
IProject prj = ResourcesPlugin.getWorkspace().getRoot()
.getProject(file.getName());
prj.create(desc, null);
prj.open(null);
try {
new ConnectProviderOperation(prj,
myRepository.getDirectory()).execute(null);
} catch (Exception e) {
Activator.logError(
"Failed to connect project to repository", e);
}
assertConnected(prj);
}
}
}
TestUtil.waitForJobs(50, 5000);
}
@SuppressWarnings("boxing")
protected void assertProjectExistence(String projectName, boolean existence) {
IProject prj = ResourcesPlugin.getWorkspace().getRoot().getProject(
projectName);
assertEquals("Project existence " + projectName, prj.exists(),
existence);
}
protected static Repository lookupRepository(File directory)
throws Exception {
return org.eclipse.egit.core.Activator.getDefault()
.getRepositoryCache().lookupRepository(directory);
}
/**
* Modify with a random content and commit.
*
* @param commitMessage
* may be null
* @throws Exception
*/
protected static void touchAndSubmit(String commitMessage) throws Exception {
String newContent = "Touched at " + System.currentTimeMillis();
touchAndSubmit(newContent, commitMessage);
}
/**
* Modify with the given content and commit.
*
* @param newContent
* new file content
* @param commitMessage
* may be null
* @throws Exception
*/
protected static void touchAndSubmit(String newContent, String commitMessage)
throws Exception {
IFile file = touch(newContent);
IFile[] committableFiles = new IFile[] { file };
ArrayList<IFile> untracked = new ArrayList<>();
untracked.addAll(Arrays.asList(committableFiles));
String message = commitMessage;
if (message == null)
message = newContent;
CommitOperation op = new CommitOperation(committableFiles,
untracked, TestUtil.TESTAUTHOR, TestUtil.TESTCOMMITTER,
message);
op.execute(null);
TestUtil.waitForJobs(50, 5000);
}
/**
* Modify with the given content.
*
* @param newContent
* new file content
* @return the modified file
* @throws Exception
*/
protected static IFile touch(final String newContent) throws Exception {
return touch(PROJ1, "folder/test.txt", newContent);
}
/**
* Modify the specified file with the given content.
*
* @param projectName
* project name
* @param filePath
* file path under the given project
* @param newContent
* new file content
* @return the modified file
* @throws Exception
*/
protected static IFile touch(String projectName, String filePath,
String newContent) throws Exception {
IProject prj = ResourcesPlugin.getWorkspace().getRoot()
.getProject(projectName);
if (!prj.isAccessible())
throw new IllegalStateException("No project to touch");
IFile file = prj.getFile(new Path(filePath));
ByteArrayInputStream inputStream = new ByteArrayInputStream(
newContent.getBytes(prj.getDefaultCharset()));
if (!file.exists())
file.create(inputStream, 0, null);
else
file.setContents(inputStream, 0, null);
TestUtil.joinJobs(JobFamilies.INDEX_DIFF_CACHE_UPDATE);
return file;
}
protected static void stage(IFile file) throws Exception {
ArrayList<IFile> unstaged = new ArrayList<>();
unstaged.addAll(Arrays.asList(new IFile[] { file }));
AddToIndexOperation op = new AddToIndexOperation(unstaged);
op.execute(null);
}
protected static void addAndCommit(IFile file, String commitMessage)
throws Exception {
IProject prj = file.getProject();
if (!prj.isAccessible())
throw new IllegalStateException("No project to touch");
IFile[] committableFiles = new IFile[] { file };
ArrayList<IFile> untracked = new ArrayList<>();
untracked.addAll(Arrays.asList(committableFiles));
CommitOperation op = new CommitOperation(committableFiles,
untracked, TestUtil.TESTAUTHOR, TestUtil.TESTCOMMITTER,
commitMessage);
op.execute(null);
TestUtil.waitForJobs(50, 5000);
}
protected static void setTestFileContent(String newContent)
throws Exception {
IProject prj = ResourcesPlugin.getWorkspace().getRoot().getProject(
PROJ1);
if (!prj.isAccessible())
throw new IllegalStateException("No project found");
IFile file = prj.getFile(new Path("folder/test.txt"));
file.refreshLocal(0, null);
file.setContents(new ByteArrayInputStream(newContent.getBytes(prj
.getDefaultCharset())), 0, null);
}
protected String getTestFileContent() throws Exception {
return getTestFileContent(FILE1);
}
protected String getTestFileContent(String fileName) throws Exception {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getProject(PROJ1)
.getFolder(FOLDER).getFile(fileName);
if (file.exists()) {
byte[] bytes = IO.readFully(file.getLocation().toFile());
return new String(bytes, file.getCharset());
}
return "";
}
/**
* @param projectExplorerTree
* @param project
* name of a project
* @return the project item pertaining to the project
*/
protected SWTBotTreeItem getProjectItem(SWTBotTree projectExplorerTree,
String project) {
return new TestUtil().getProjectItems(projectExplorerTree, project)[0];
}
protected void pressAltAndChar(SWTBotShell shell, char charToPress) {
Display display = PlatformUI.getWorkbench().getDisplay();
Event evt = new Event();
// Alt down
evt.type = SWT.KeyDown;
evt.item = shell.widget;
evt.keyCode = SWT.ALT;
display.post(evt);
// G down
evt.keyCode = 0;
evt.character = charToPress;
display.post(evt);
// G up
evt.type = SWT.KeyUp;
display.post(evt);
// Alt up
evt.keyCode = SWT.ALT;
evt.character = ' ';
display.post(evt);
}
protected static Collection<Ref> getRemoteRefs(URIish uri) throws Exception {
int timeout = 20;
ListRemoteOperation listRemoteOp = new ListRemoteOperation(uri,
timeout);
listRemoteOp.run(null);
return listRemoteOp.getRemoteRefs();
}
}