/******************************************************************************* * Copyright (c) 2000, 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 Corporation - initial API and implementation * Alexander Kurtakov <akurtako@redhat.com> - Bug 459343 *******************************************************************************/ package org.eclipse.core.tests.internal.watson; import java.util.ArrayList; import java.util.Stack; import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.core.internal.watson.*; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; /** * Unit tests for <code>ElementTreeIterator</code>. */ public class ElementTreeIteratorTest extends WatsonTest { public ElementTreeIteratorTest() { super(null); } public ElementTreeIteratorTest(String name) { super(name); } @Override protected void setUp() throws Exception { // do nothing } static void setupElementTree(ElementTree tree, int num) { final IElementTreeData data = new IElementTreeData() { @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { } return null; } }; IPath sol = Path.ROOT.append("sol"); tree.createElement(sol, data); for (int p = 0; p < num; p++) { IPath proj = sol.append("proj" + p); tree.createElement(proj, data); for (int k = 0; k < num; k++) { IPath folder = proj.append("folder" + k); tree.createElement(folder, data); for (int c = 0; c < num; c++) { IPath file = folder.append("file" + c); tree.createElement(file, data); } } } } public void testConcurrentModification() { //the dining detectives problem ElementTree baseTree = new ElementTree(); int n = 3; setupElementTree(baseTree, n); baseTree.immutable(); final ElementTree tree = baseTree.newEmptyDelta(); modifyTree(tree); final ArrayList<Object> elts = new ArrayList<>(); final IElementContentVisitor visitor = (tree1, requestor, info) -> { elts.add(info); return true; }; Thread reader = new Thread((Runnable) () -> { for (int i = 0; i < 80000; i++) { new ElementTreeIterator(tree, Path.ROOT).iterate(visitor); } }, "Holmes (reader)"); Thread writer = new Thread((Runnable) () -> { for (int i = 0; i < 1000; i++) { modifyTree(tree); recursiveDelete(tree, Path.ROOT); setupElementTree(tree, 3); } }, "Doyle (writer)"); reader.start(); writer.start(); //wait for both threads to finish try { reader.join(); writer.join(); } catch (InterruptedException e) { } } public static Test suite() { TestSuite suite = new TestSuite(ElementTreeIteratorTest.class); return suite; } @Override protected void tearDown() throws Exception { //ElementTree tests don't use the CoreTest infrastructure } public void testContentIterator() { ElementTree tree = new ElementTree(); int n = 3; setupElementTree(tree, n); final ArrayList<IPath> elts = new ArrayList<>(); IElementContentVisitor elementVisitor = (tree1, requestor, info) -> { elts.add(requestor.requestPath()); return true; }; new ElementTreeIterator(tree, Path.ROOT).iterate(elementVisitor); assertEquals("1", 2 + n + n * n + n * n * n, elts.size()); elts.clear(); IPath innerElement = Path.ROOT.append("sol").append("proj1"); new ElementTreeIterator(tree, innerElement).iterate(elementVisitor); assertEquals("2", 1 + n + n * n, elts.size()); } /** * Method deleteChild. * @param path */ void recursiveDelete(ElementTree tree, IPath path) { IPath[] children = tree.getChildren(path); for (IPath element : children) { recursiveDelete(tree, element); } tree.deleteElement(path); } protected void modifyTree(ElementTree tree) { class MyStack extends Stack<IPath> { /** * All serializable objects should have a stable serialVersionUID */ private static final long serialVersionUID = 1L; public void pushAll(IPath[] array) { for (IPath element : array) { push(element); } } } MyStack toModify = new MyStack(); IPath[] children = tree.getChildren(Path.ROOT); toModify.pushAll(children); while (!toModify.isEmpty()) { IPath visit = toModify.pop(); tree.openElementData(visit); toModify.pushAll(tree.getChildren(visit)); } } }