package com.sap.ide.cts.editor.test.util;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
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.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.junit.After;
import org.junit.Before;
/**
* A JUnit 4 compatible, lightweight version of {@link ProjectBasedTest}
*
* @author C5126871, D049157
*
*/
@SuppressWarnings("restriction")
public abstract class ProjectConnectionBasedTest {
private IProject mProject;
private final Set<ResourceSet> mConnections = new HashSet<ResourceSet>();
/**
* Set this to true in your testclass constructor to retrieve inMemory connections only.
* Those cannot be saved, but instead come with a great speed improvement.
*/
protected boolean memoryChangesOnly = false;
private static final String MOIN_NATURE = "com.sap.mi.fwk.dcfwk.MoinNature";
private static final String PLUGIN_NATURE = org.eclipse.pde.internal.core.natures.PDE.PLUGIN_NATURE;
@Before
public void setUp() throws CoreException, IOException {
mProject = ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName());
if (!memoryChangesOnly || !mProject.exists()) {
if (mProject.exists()) {
// always delete old project before trying to write a new project
// allows to mix memory only and persistent tests in the same suite
deleteProject();
}
InputStream data = getProjectContentAsStream();
mProject = createProjectWithData(getProjectName(), data);
refreshProject(mProject);
}
}
@After
public void tearDown() throws Exception {
closeConnections();
mConnections.clear();
if (!memoryChangesOnly) {
deleteProject();
}
}
private IProject createProjectWithData(String projectName, InputStream data) throws CoreException, IOException {
final IProject prj = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
IProjectDescription desc;
prj.create(null);
prj.open(null);
desc = ResourcesPlugin.getWorkspace().newProjectDescription(projectName);
desc.setNatureIds(new String[] {PLUGIN_NATURE, MOIN_NATURE });
prj.setDescription(desc, null);
loadData(ProjectConnectionBasedTest.class.getResourceAsStream("project.zip"), prj);
loadData(data, prj);
return prj;
}
/**
* This long running method forces a full refresh of the project.
*
* The project and all partitions are completely re-read from
* the filesystem and MOIN is in a clean state again.
*
* @param project
*/
private void refreshProject(final IProject prj) {
Job refresh = new Job("Refresh project") {
@Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("Refresh Test Project from Filesystem", 20);
try {
prj.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 10));
// force a full refresh
// ModelManager.getInstance().refreshFromFileSystem(mProject, new SubProgressMonitor(monitor, 10));
} catch (CoreException e) {
fail("Failed to refresh project");
}
monitor.done();
return Status.OK_STATUS;
}
};
refresh.schedule();
try {
refresh.join();
} catch (InterruptedException e) {
fail("Failed to refresh project");
}
}
private void deleteProject() throws CoreException {
if (mProject != null) {
mProject.delete(true, true, null);
mProject = null;
}
}
private static void loadData(InputStream data, IProject project) throws IOException {
String zipFilename = FileServices.getTempDir() + File.separator + "moin_sample_data.zip"; //$NON-NLS-1$
FileServices.streamToFile(zipFilename, data);
// unzip into the project directory:
String targetDirectory = project.getLocation().toOSString();
ZipService.unzipDir(zipFilename, targetDirectory);
}
public IProject getProject() {
return mProject;
}
/**
* Data for the desired project.
* Will be called before each testcase.
*
* @return
*/
protected abstract InputStream getProjectContentAsStream();
/**
* Name of the desired project.
* Will be recreated upon each testcase.
*
* @return
*/
protected abstract String getProjectName();
/**
* Creates a connection for the test's project. The returned is always a new
* one, and is closed on {@link #tearDown()} latest.
*
* @return a new connection
*
* @see #getConnections()
* @see #closeConnections()
*/
protected ResourceSet createConnection() {
final ResourceSet[] con = new ResourceSet[1];
Job creator = new Job("Create ResourceSet") {
@Override
protected IStatus run(IProgressMonitor monitor) {
con[0] = ConnectionManager.getInstance().createConnection(getProject());
return Status.OK_STATUS;
}
};
creator.schedule();
try {
creator.join();
} catch (InterruptedException e) {
fail(e.getMessage());
}
if (memoryChangesOnly) {
con[0].enableMemoryChangeOnly();
}
mConnections.add(con[0]);
return con[0];
}
/**
* @return all connections that this test has created up to now
*
* @see #createConnection()
*/
protected Set<ResourceSet> getConnections() {
return mConnections;
}
/**
* Closes all connections that this test has created, i.e. <em>only the ones
* that have been created with {@link #createConnection()}</em>.
*
* @see #getConnections()
* @see #createConnection()
*/
protected void closeConnections() {
Set<ResourceSet> connections = getConnections();
for (ResourceSet connection : connections) {
if (connection != null && connection.isAlive()) {
connection.close();
}
}
}
}