/*******************************************************************************
 * Copyright (c) 2006, 2015 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 ******************************************************************************/

package org.eclipse.core.tests.resources.regression;

import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.tests.harness.CoreTest;

/**
 * Tests an error that occurs when a thread tries to read the workspace
 * during snapshot.  Since snapshot collapses unused trees, it is a destructive
 * operation on the tree's parent chain.  Any reader traversing the tree parent
 * chain during that destructive operation risks encountering the tree in a
 * malformed state.  The fix was to synchronize the routine that collapses
 * unused trees in ElementTree.
 */
public class Bug_134364 extends CoreTest {
	public static Test suite() {
		return new TestSuite(Bug_134364.class);
	}

	public Bug_134364() {
		super("");
	}

	public Bug_134364(String name) {
		super(name);
	}

	/**
	 * Creates a project with a builder attached
	 */
	private IProject createOtherProject() throws CoreException {
		final IWorkspace workspace = ResourcesPlugin.getWorkspace();
		IProject other = workspace.getRoot().getProject("Other");
		IProjectDescription desc = workspace.newProjectDescription(other.getName());
		ICommand command = desc.newCommand();
		command.setBuilderName("org.eclipse.core.tests.resources.sortbuilder");
		desc.setBuildSpec(new ICommand[] {command});
		other.create(desc, null);
		other.open(null);
		return other;
	}

	public void test1() throws Exception {
		final IProject other = createOtherProject();
		final boolean[] done = new boolean[] {false};
		final RuntimeException[] failure = new RuntimeException[1];
		//create a job that continually tries to read the workspace tree
		new Job("Reader-134364") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
				try {
					while (!done[0]) {
						root.getProjects();
						try {
							other.members();
						} catch (CoreException e) {
							//ignore
						}
					}
					return Status.OK_STATUS;
				} catch (RuntimeException e) {
					failure[0] = e;
					throw e;
				}
			}
		}.schedule();
		//create a job that continually creates projects, thus causing snapshots to occur
		Job writer = new Job("Writer-134364") {
			@Override
			public IStatus run(IProgressMonitor monitor) {
				IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestBug134364");
				for (int i = 0; i < 100; i++) {
					if (failure[0] != null) {
						System.out.println("Failure: " + i);
						break;
					}
					try {
						//create a few extra tree layers
						project.create(null);
						project.open(null);
						project.touch(null);
						project.delete(IResource.NONE, null);
					} catch (CoreException e) {
						//just bail out
						e.printStackTrace();
						return Status.OK_STATUS;
					}
				}
				return Status.OK_STATUS;
			}
		};
		writer.schedule();
		writer.join();
		done[0] = true;
		if (failure[0] != null) {
			fail("1.0", failure[0]);
		}
	}
}
