1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.scenegraph.tests;
\r
14 import static junit.framework.Assert.assertEquals;
\r
15 import static junit.framework.Assert.assertSame;
\r
17 import java.util.ArrayList;
\r
18 import java.util.List;
\r
19 import java.util.UUID;
\r
20 import java.util.concurrent.BrokenBarrierException;
\r
21 import java.util.concurrent.CyclicBarrier;
\r
22 import java.util.concurrent.Semaphore;
\r
23 import java.util.concurrent.atomic.AtomicBoolean;
\r
25 import org.junit.Test;
\r
26 import org.simantics.scenegraph.INode;
\r
27 import org.simantics.scenegraph.ParentNode;
\r
28 import org.simantics.scenegraph.g2d.G2DParentNode;
\r
29 import org.simantics.scenegraph.g2d.G2DSceneGraph;
\r
30 import org.simantics.scenegraph.g2d.nodes.DataNode;
\r
31 import org.simantics.scenegraph.g2d.nodes.NavigationNode;
\r
32 import org.simantics.scenegraph.utils.NodeUtil;
\r
36 * @author Tuukka Lehtonen
\r
38 public class LookupServiceSynchronizationTest {
\r
40 public static final int ITERATIONS = 10;
\r
41 public static final int ITERATION_TIME_MS = 1000;
\r
42 public static final int THREADS = 16;
\r
44 AtomicBoolean endTest;
\r
45 CyclicBarrier startBarrier;
\r
48 G2DSceneGraph root = new G2DSceneGraph();
\r
49 List<INode> nodes = new ArrayList<INode>();
\r
50 List<String> nodeIds = new ArrayList<String>();
\r
51 List<String> mappedIds = new ArrayList<String>();
\r
53 List<Throwable> errors = new ArrayList<Throwable>();
\r
55 public class Lookup implements Runnable {
\r
58 public Lookup(String id, INode node) {
\r
65 System.out.println("started " + Thread.currentThread().getName());
\r
67 startBarrier.await();
\r
68 while (!endTest.get()) {
\r
70 INode n = NodeUtil.lookup(this.node, this.id);
\r
71 String id = NodeUtil.lookupId(this.node);
\r
73 assertSame(this.node, n);
\r
75 assertSame(this.id, id);
\r
77 } catch (InterruptedException e) {
\r
79 } catch (BrokenBarrierException e) {
\r
82 System.out.println("ending " + Thread.currentThread().getName());
\r
89 public class Mapper implements Runnable {
\r
92 public Mapper(String id, INode node) {
\r
99 System.out.println("started " + Thread.currentThread().getName());
\r
100 System.out.flush();
\r
101 startBarrier.await();
\r
102 for (int i = 0; !endTest.get(); ++i) {
\r
104 NodeUtil.map(node, id);
\r
106 NodeUtil.unmap(node);
\r
110 } catch (InterruptedException e) {
\r
112 } catch (BrokenBarrierException e) {
\r
115 System.out.println("ending " + Thread.currentThread().getName());
\r
116 System.out.flush();
\r
122 <T extends INode> T addAndMapNode(ParentNode<?> parent, String id, Class<T> clazz) {
\r
123 T node = parent.addNode(id, clazz);
\r
126 NodeUtil.map(node, id);
\r
130 <T extends INode> T addNode(ParentNode<?> parent, String id, Class<T> clazz) {
\r
131 T node = parent.addNode(id, clazz);
\r
137 <T extends INode> T addNode(ParentNode<?> parent, Class<T> clazz) {
\r
138 return addNode(parent, UUID.randomUUID().toString(), clazz);
\r
142 public void testLookup() throws Exception {
\r
143 NavigationNode nav = addAndMapNode(root, "navigation", NavigationNode.class);
\r
144 DataNode data = addAndMapNode(root, "data", DataNode.class);
\r
145 G2DParentNode elements = addNode(nav, "elements", G2DParentNode.class);
\r
146 @SuppressWarnings("unused")
\r
147 G2DParentNode ghosts = addNode(nav, "ghosts", G2DParentNode.class);
\r
150 assertSame(nav, root.lookupNode("navigation"));
\r
151 assertSame(data, root.lookupNode("data"));
\r
152 assertSame(nav, NodeUtil.lookup(nav, "navigation"));
\r
153 assertSame(data, NodeUtil.lookup(data, "data"));
\r
155 for (int iter = 1; iter <= ITERATIONS; ++iter) {
\r
156 System.out.println("Starting iteration " + iter);
\r
157 System.out.flush();
\r
159 endTest = new AtomicBoolean(false);
\r
160 startBarrier = new CyclicBarrier(THREADS * 2 + 1);
\r
161 ended = new Semaphore(0);
\r
163 for (int i = 0; i < THREADS; ++i) {
\r
164 String id = UUID.randomUUID().toString();
\r
165 INode node = addNode(elements, id, G2DParentNode.class);
\r
166 new Thread(new Mapper(id, node), "Mapper-" + i).start();
\r
167 new Thread(new Lookup(id, node), "Lookup-" + i).start();
\r
170 startBarrier.await();
\r
171 // Sleep for the testing period
\r
172 synchronized (this) {
\r
173 wait(ITERATION_TIME_MS);
\r
175 // Wait for threads to end
\r
176 System.out.println("Ending iteration " + iter);
\r
177 System.out.flush();
\r
179 ended.acquire(2*THREADS);
\r
180 System.out.println("Iteration " + iter + " ended");
\r
183 assertEquals(errors.size(), 0);
\r