/*******************************************************************************
 * Copyright (c) 2004, 2017 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 - Initial API and implementation
 *******************************************************************************/
package org.eclipse.core.tests.internal.resources;

import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.tests.harness.CancelingProgressMonitor;
import org.eclipse.core.tests.harness.TestBarrier;
import org.eclipse.core.tests.resources.ResourceTest;

/**
 * Tests concurrency issues when dealing with operations on the workspace
 */
public class WorkspaceConcurrencyTest extends ResourceTest {

	public static Test suite() {
		return new TestSuite(WorkspaceConcurrencyTest.class);
	}

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

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

	private void sleep(long duration) {
		try {
			Thread.sleep(duration);
		} catch (InterruptedException e) {
			//ignore
		}
	}

	public void testEndRuleInWorkspaceOperation() {
		try {
			final IProject project = getWorkspace().getRoot().getProject("testEndRuleInWorkspaceOperation");
			getWorkspace().run((IWorkspaceRunnable) monitor -> Job.getJobManager().endRule(project), project, IResource.NONE, getMonitor());
			//should have failed
			fail("1.0");
		} catch (CoreException e) {
			fail("1.99", e);
		} catch (RuntimeException e) {
			//expected
		}
	}

	/**
	 * Tests that it is possible to cancel a workspace operation when it is blocked
	 * by activity in another thread. This is a regression test for bug 56118.
	 */
	public void testCancelOnBlocked() {
		//create a dummy project
		ensureExistsInWorkspace(getWorkspace().getRoot().getProject("P1"), true);
		//add a resource change listener that blocks forever, thus
		//simulating a scenario where workspace lock is held indefinitely
		final int[] barrier = new int[1];
		final Throwable[] error = new Throwable[1];
		IResourceChangeListener listener = event -> {
			//block until we are told to do otherwise
			barrier[0] = TestBarrier.STATUS_START;
			try {
				TestBarrier.waitForStatus(barrier, TestBarrier.STATUS_DONE);
			} catch (Throwable e) {
				error[0] = e;
			}
		};
		getWorkspace().addResourceChangeListener(listener);
		try {
			//create a thread that modifies the workspace. This should
			//hang indefinitely due to the misbehaving listener
			TestWorkspaceJob testJob = new TestWorkspaceJob(10);
			testJob.setTouch(true);
			testJob.setRule(getWorkspace().getRoot());
			testJob.schedule();

			//wait until blocked on the listener
			TestBarrier.waitForStatus(barrier, TestBarrier.STATUS_START);

			//create a second thread that attempts to modify the workspace, but immediately
			//cancels itself. This thread should terminate immediately with a cancelation exception
			final boolean[] canceled = new boolean[] {false};
			Thread t2 = new Thread(() -> {
				try {
					getWorkspace().run((IWorkspaceRunnable) monitor -> {
						//no-op
					}, new CancelingProgressMonitor());
				} catch (CoreException e1) {
					fail("1.99", e1);
				} catch (OperationCanceledException e2) {
					canceled[0] = true;
				}
			});
			t2.start();
			try {
				t2.join();
			} catch (InterruptedException e) {
				fail("1.88", e);
			}
			//should have canceled
			assertTrue("2.0", canceled[0]);

			//finally release the listener and ensure the first thread completes
			barrier[0] = TestBarrier.STATUS_DONE;
			try {
				testJob.join();
			} catch (InterruptedException e1) {
				//ignore
			}
			if (error[0] != null)
				fail("3.0", error[0]);
		} finally {
			getWorkspace().removeResourceChangeListener(listener);
		}
	}

	/**
	 * Tests calling IWorkspace.run with a non-workspace rule.  This should be
	 * allowed. This is a regression test for bug 60114.
	 */
	public void testRunnableWithOtherRule() {
		ISchedulingRule rule = new ISchedulingRule() {
			@Override
			public boolean contains(ISchedulingRule rule) {
				return rule == this;
			}

			@Override
			public boolean isConflicting(ISchedulingRule rule) {
				return rule == this;
			}
		};
		try {
			getWorkspace().run((IWorkspaceRunnable) monitor -> {
				//noop
			}, rule, IResource.NONE, getMonitor());
		} catch (CoreException e) {
			fail("1.99", e);
		}
	}

	/**
	 * Tests three overlapping jobs
	 *  - Job 1 (root rule) does a build.
	 *  - Job 2 (null rule) overlaps Job 1 and has null scheduling rule
	 *  - Job 3 (project rule) overlaps Job 2
	 *
	 * The POST_BUILD event should occur at the end of Job 1. If it
	 * is delayed until the end of Job 3, an appropriate scheduling rule
	 * will not be available and it will fail.
	 * This is a regression test for bug 	62927.
	 */
	public void testRunWhileBuilding() {
		final IWorkspace workspace = ResourcesPlugin.getWorkspace();
		//create a POST_BUILD listener that will touch a project
		final IProject touch = workspace.getRoot().getProject("ToTouch");
		final IProject rule = workspace.getRoot().getProject("jobThree");
		final IFile ruleFile = rule.getFile("somefile.txt");
		ensureExistsInWorkspace(rule, true);
		ensureExistsInWorkspace(touch, true);
		ensureExistsInWorkspace(ruleFile, true);
		final Throwable[] failure = new Throwable[1];
		IResourceChangeListener listener = event -> {
			try {
				touch.touch(null);
			} catch (CoreException e1) {
				failure[0] = e1;
			} catch (RuntimeException e2) {
				failure[0] = e2;
			}
		};
		workspace.addResourceChangeListener(listener, IResourceChangeEvent.POST_BUILD);
		try {
			//create one job that does a build, and then waits
			final int[] status = new int[3];
			Job jobOne = new Job("jobOne") {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					try {
						workspace.run((IWorkspaceRunnable) monitor1 -> {
							//do a build
							workspace.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor1);
							//signal that the job has done the build
							status[0] = TestBarrier.STATUS_RUNNING;
							//wait for job two to start
							TestBarrier.waitForStatus(status, 0, TestBarrier.STATUS_WAIT_FOR_DONE);
						}, null);
					} catch (CoreException e) {
						return e.getStatus();
					}
					return Status.OK_STATUS;
				}
			};
			//schedule and wait for job one to start
			jobOne.schedule();
			TestBarrier.waitForStatus(status, 0, TestBarrier.STATUS_RUNNING);

			//create job two that does an empty workspace operation
			Job jobTwo = new Job("jobTwo") {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					try {
						workspace.run((IWorkspaceRunnable) monitor1 -> {
							//signal that this job has started
							status[1] = TestBarrier.STATUS_RUNNING;
							//let job one finish
							status[0] = TestBarrier.STATUS_WAIT_FOR_DONE;
							//wait for job three to start
							TestBarrier.waitForStatus(status, 1, TestBarrier.STATUS_WAIT_FOR_DONE);
						}, null, IResource.NONE, null);
					} catch (CoreException e) {
						return e.getStatus();
					}
					return Status.OK_STATUS;
				}
			};
			jobTwo.schedule();
			//create job three that has a non-null rule
			Job jobThree = new Job("jobThree") {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					try {
						workspace.run((IWorkspaceRunnable) monitor1 -> {
							//signal that this job has started
							status[2] = TestBarrier.STATUS_RUNNING;
							//let job two finish
							status[1] = TestBarrier.STATUS_WAIT_FOR_DONE;
							//ensure this job does something so the build listener runs
							ruleFile.touch(null);
							//wait for the ok to complete
							TestBarrier.waitForStatus(status, 2, TestBarrier.STATUS_WAIT_FOR_DONE);
						}, workspace.getRuleFactory().modifyRule(ruleFile), IResource.NONE, null);
					} catch (CoreException e) {
						return e.getStatus();
					}
					return Status.OK_STATUS;
				}
			};
			jobThree.schedule();
			//wait for job two to complete
			waitForCompletion(jobTwo);

			//let job three complete
			status[2] = TestBarrier.STATUS_WAIT_FOR_DONE;

			//wait for job three to complete
			waitForCompletion(jobThree);

			//ensure no jobs failed
			IStatus result = jobOne.getResult();
			if (!result.isOK())
				fail("1.0", new CoreException(result));
			result = jobTwo.getResult();
			if (!result.isOK())
				fail("1.1", new CoreException(result));
			result = jobThree.getResult();
			if (!result.isOK())
				fail("1.2", new CoreException(result));

			if (failure[0] != null)
				fail("1.3", failure[0]);
		} finally {
			//ensure listener is removed
			workspace.removeResourceChangeListener(listener);
		}
	}

	private void waitForCompletion(Job job) {
		int i = 0;
		while (job.getState() != Job.NONE) {
			sleep(100);
			//sanity test to avoid hanging tests
			assertTrue("Timeout waiting for job to complete", i++ < 1000);
		}
	}
}
