blob: 2a521f28db6f82895dbbedb4971f2a69d5110a9a [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea;
import com.intellij.idea.IdeaTestApplication;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.TestLoggerFactory;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.ui.UIUtil;
import cucumber.annotation.After;
import cucumber.annotation.Before;
import cucumber.annotation.Order;
import cucumber.runtime.ScenarioResult;
import git4idea.commands.Git;
import git4idea.commands.GitHttpAuthService;
import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepository;
import git4idea.test.GitExecutor;
import git4idea.test.GitHttpAuthTestService;
import git4idea.test.GitTestUtil;
import git4idea.test.MockVcsHelper;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.picocontainer.MutablePicoContainer;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import static com.intellij.openapi.vcs.Executor.cd;
import static com.intellij.openapi.vcs.Executor.mkdir;
/**
* <p>The container of test environment variables which should be visible from any step definition script.</p>
* <p>Most of the fields are populated in the Before hook of the {@link GeneralStepdefs}.</p>
*/
public class GitCucumberWorld {
static {
Logger.setFactory(TestLoggerFactory.class);
}
public static String myTestRoot;
public static String myProjectRoot;
public static VirtualFile myProjectDir;
public static Project myProject;
public static GitPlatformFacade myPlatformFacade;
public static Git myGit;
public static GitRepository myRepository;
public static GitVcsSettings mySettings;
public static ChangeListManagerImpl myChangeListManager;
public static GitVcs myVcs;
public static MockVcsHelper myVcsHelper;
public static TestVcsNotifier myNotificator;
public static GitHttpAuthTestService myHttpAuthService; // only with @remote tag
public static GitTestVirtualCommitsHolder virtualCommits;
private static Collection<Future> myAsyncTasks;
private final Logger LOG = Logger.getInstance(GitCucumberWorld.class);
private IdeaProjectTestFixture myProjectFixture;
private String myTestName;
@Before
@Order(0)
public void setUp() throws Throwable {
PlatformTestCase.initPlatformLangPrefix();
IdeaTestApplication.getInstance(null);
myTestName = createTestName();
myProjectFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(myTestName).getFixture();
edt(new ThrowableRunnable<Exception>() {
@Override
public void run() throws Exception {
myProjectFixture.setUp();
}
});
myProject = myProjectFixture.getProject();
((ProjectComponent)ChangeListManager.getInstance(myProject)).projectOpened();
((ProjectComponent)VcsDirtyScopeManager.getInstance(myProject)).projectOpened();
myProjectRoot = myProject.getBasePath();
myProjectDir = myProject.getBaseDir();
myTestRoot = myProjectRoot;
myPlatformFacade = ServiceManager.getService(myProject, GitPlatformFacade.class);
myGit = ServiceManager.getService(myProject, Git.class);
mySettings = myPlatformFacade.getSettings(myProject);
mySettings.getAppSettings().setPathToGit(GitExecutor.PathHolder.GIT_EXECUTABLE);
// dynamic overriding is used instead of making it in plugin.xml,
// because MockVcsHelper is not ready to be a full featured implementation for all tests.
myVcsHelper = overrideService(myProject, AbstractVcsHelper.class, MockVcsHelper.class);
myChangeListManager = (ChangeListManagerImpl)myPlatformFacade.getChangeListManager(myProject);
myNotificator = (TestVcsNotifier)ServiceManager.getService(myProject, VcsNotifier.class);
myVcs = GitVcs.getInstance(myProject);
virtualCommits = new GitTestVirtualCommitsHolder();
myAsyncTasks = new ArrayList<Future>();
cd(myProjectRoot);
myRepository = GitTestUtil.createRepository(myProject, myProjectRoot);
ProjectLevelVcsManagerImpl vcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject);
AbstractVcs vcs = vcsManager.findVcsByName("Git");
Assert.assertEquals(1, vcsManager.getRootsUnderVcs(vcs).length);
GitTestUtil.assumeSupportedGitVersion(myVcs);
LOG.info(getStartTestMarker());
}
private String getStartTestMarker() {
return "Starting " + myTestName;
}
// TODO should take actual feature name once we migrate to more recent cucumber lib
private String createTestName() {
return getClass().getName() + "-" + new Random().nextInt();
}
@Before("@remote")
@Order(1)
public void setUpRemoteOperations() {
GitTestUtil.setDefaultBuiltInServerPort();
myHttpAuthService = (GitHttpAuthTestService)ServiceManager.getService(GitHttpAuthService.class);
}
@Before("@nestedroot")
@Order(2)
public void setUpStandardMultipleRootsConfig() {
cd(myProjectRoot);
File community = mkdir("community");
GitTestUtil.createRepository(myProject, community.getPath());
}
@After("@remote")
@Order(5)
public void tearDownRemoteOperations() {
}
@After
@Order(4)
public void waitForPendingTasks() throws InterruptedException, ExecutionException, TimeoutException {
for (Future future : myAsyncTasks) {
future.get(30, TimeUnit.SECONDS);
}
}
@After
@Order(3)
public void tearDownFixture() throws Exception {
edt(new ThrowableRunnable<Exception>() {
@Override
public void run() throws Exception {
myProjectFixture.tearDown();
}
});
}
@After
@Order(2)
public void cleanupDir() {
FileUtil.delete(new File(myTestRoot));
}
@After
@Order(1)
public void cleanupWorld() throws IllegalAccessException {
for (Field field : GitCucumberWorld.class.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) {
field.set(null, null);
}
}
}
@After
@Order(0)
public void dumpToLog(@NotNull ScenarioResult result) throws IOException {
if (result.isFailed()) {
TestLoggerFactory.dumpLogToStdout(getStartTestMarker());
}
}
public static void executeOnPooledThread(Runnable runnable) {
myAsyncTasks.add(ApplicationManager.getApplication().executeOnPooledThread(runnable));
}
@SuppressWarnings("unchecked")
private static <T> T overrideService(@NotNull Project project, Class<? super T> serviceInterface, Class<T> serviceImplementation) {
String key = serviceInterface.getName();
MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer();
picoContainer.unregisterComponent(key);
picoContainer.registerComponentImplementation(key, serviceImplementation);
return (T) ServiceManager.getService(project, serviceInterface);
}
private static void edt(@NotNull final ThrowableRunnable<Exception> runnable) throws Exception {
final AtomicReference<Exception> exception = new AtomicReference<Exception>();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
try {
runnable.run();
}
catch (Exception throwable) {
exception.set(throwable);
}
}
});
//noinspection ThrowableResultOfMethodCallIgnored
if (exception.get() != null) {
throw exception.get();
}
}
}