/*******************************************************************************
* Copyright (c) 2016 Red Hat Inc. 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
*
* Contributors:
* Red Hat - Initial Contribution
*******************************************************************************/
package org.eclipse.linuxtools.internal.docker.ui.testutils;
import static org.junit.Assert.fail;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ui.dialogs.IOverwriteQuery;
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
import org.junit.rules.ExternalResource;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* JUnit {@link TestRule} to initialize a {@link IProject} in the test
* workspace, by reading the {@link RunWithProject} annotation on the test
* method.
*/
public class ProjectInitializationRule extends ExternalResource {
private Description description;
private IProject project = null;
public IProject getProject() {
return this.project;
}
@Override
public Statement apply(final Statement base, final Description description) {
this.description = description;
return super.apply(base, description);
}
@Override
protected void before() throws Throwable {
if (description == null) {
fail("No method description available while trying to setup test project");
}
final String projectName = getProjectName();
final IWorkspace junitWorkspace = ResourcesPlugin.getWorkspace();
this.project = getTargetWorkspaceProject(getSampleProjectPath(projectName), junitWorkspace);
}
/**
* @return the name of the project to setup before running the JUnit test.
* @throws NoSuchMethodException
* @throws ClassNotFoundException
*/
private String getProjectName() throws NoSuchMethodException, ClassNotFoundException {
final String className = description.getClassName();
final String methodName = description.getMethodName();
final Class<?> testClass = Class.forName(className);
final Method testMethod = testClass.getMethod(methodName);
final RunWithProject runWithProjectMethodAnnotation = testMethod.getAnnotation(RunWithProject.class);
if (runWithProjectMethodAnnotation != null) {
return runWithProjectMethodAnnotation.value();
}
final RunWithProject runWithProjectTypeAnnotation = testClass.getAnnotation(RunWithProject.class);
if (runWithProjectTypeAnnotation != null) {
return runWithProjectTypeAnnotation.value();
}
fail("No '@RunWithProject' annotation found while running test " + className + "." + methodName);
return null;
}
/**
* @param projectName
* the name of the project
* @return the {@link IPath} to the given project, in an absolute form.
*/
public static IPath getSampleProjectPath(final String projectName) {
if (System.getProperty("user.dir") != null) {
return new Path(System.getProperty("user.dir")).append("projects").append(projectName).makeAbsolute();
}
fail("The sample project was not found in the launcher workspace under name '" + projectName + "'");
return null;
}
/**
* Creates or opens the project in the target/JUnit workspace.
*
* @param projectSourcePath
* the absolute path to the project
* @param targetWorkspace
* the target workspace in which the project should be created
* @return the project
* @throws CoreException
* @throws InvocationTargetException
* @throws InterruptedException
*/
public static IProject getTargetWorkspaceProject(final IPath projectSourcePath, final IWorkspace targetWorkspace)
throws CoreException, InvocationTargetException, InterruptedException {
final IPath dotProjectPath = projectSourcePath.addTrailingSeparator().append(".project");
final IProjectDescription description = targetWorkspace.loadProjectDescription(dotProjectPath);
final String projectName = description.getName();
final IProject project = targetWorkspace.getRoot().getProject(projectName);
if (project.exists()
&& !targetWorkspace.getRoot().getFile(project.getFile(".project").getFullPath()).exists()) {
project.delete(true, null);
} else if (project.exists() && !project.isOpen()) {
project.open(null);
} else if (!project.exists()) {
createProject(description, projectName, targetWorkspace, project);
final SyncFileSystemStructureProvider syncFileSystemStructureProvider = new SyncFileSystemStructureProvider.Builder(
projectSourcePath, project.getLocation()).ignoreRelativeSourcePaths(".svn", ".git", "target", "bin")
.build();
final List<File> filesToImport = syncFileSystemStructureProvider.getChildren(projectSourcePath.toFile());
if (filesToImport != null && filesToImport.size() > 0) {
ImportOperation operation = new ImportOperation(project.getFullPath(), projectSourcePath.toFile(),
syncFileSystemStructureProvider, pathString -> IOverwriteQuery.YES, filesToImport);
operation.setContext(null);
// need to overwrite modified files
operation.setOverwriteResources(true);
operation.setCreateContainerStructure(false);
operation.run(null);
}
}
return project;
}
/**
* @param description
* @param projectName
* @param workspace
* @param project
* @throws InvocationTargetException
* @throws InterruptedException
* @throws CoreException
* @throws OperationCanceledException
*/
static void createProject(final IProjectDescription description, final String projectName,
final IWorkspace workspace, final IProject project)
throws InvocationTargetException, OperationCanceledException, CoreException, InterruptedException {
// import from file system
// import project from location copying files - use default project
// location for this workspace
// if location is null, project already exists in this location or
// some error condition occurred.
final IProjectDescription desc = workspace.newProjectDescription(projectName);
desc.setBuildSpec(description.getBuildSpec());
desc.setComment(description.getComment());
desc.setDynamicReferences(description.getDynamicReferences());
desc.setNatureIds(description.getNatureIds());
desc.setReferencedProjects(description.getReferencedProjects());
try {
project.create(desc, null);
project.open(IResource.BACKGROUND_REFRESH, null);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
buildProject(project);
}
/**
* Builds the given project
*
* @param project
* @throws CoreException
* @throws OperationCanceledException
* @throws InterruptedException
*/
public static void buildProject(final IProject project)
throws CoreException, OperationCanceledException, InterruptedException {
project.refreshLocal(IResource.DEPTH_INFINITE, null);
project.build(IncrementalProjectBuilder.FULL_BUILD, null);
Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_BUILD, null);
}
}