/* * Copyright 2009 Amit Levy, Jeff Prouty, Rylan Hawkins * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.washington.cs.cse490h.donut.util; import java.util.ArrayList; import java.util.List; import java.util.PriorityQueue; import edu.washington.cs.cse490h.donut.business.KeyId; import edu.washington.cs.cse490h.donut.business.Node; import edu.washington.cs.cse490h.donut.server.DonutClient; import edu.washington.cs.cse490h.donut.service.LocalLocatorClientFactory; import edu.washington.cs.cse490h.donut.service.NodeLocator; import edu.washington.cs.cse490h.donut.service.RetryFailedException; import edu.washington.cs.cse490h.donut.service.KeyLocator.Iface; import edu.washington.cs.cse490h.donut.service.application.DonutInMemoryHashTableService; /** * <p> * Provides a framework for setting up, running, and testing an in memory Donut ring. * </p> * <p> * Example usage: Joins three nodes and drops one. * * <pre> * DonutTestRunner donutTestRunner = new DonutTestRunner(0x0L, 0xCF00L, -0x4444L); * donutTestRunner.addEvent(0).join(0, 0); * donutTestRunner.addEvent(1000).join(1, 0); * donutTestRunner.addEvent(2000).join(2, 0); * donutTestRunner.addEvent(3000).leave(2); * donutTestRunner.addEvent(4000).test(new DonutTestCase() { * public void test() { * assertEquals(...) * ... * } * }); * donutTestRunner.run(); * </pre> * * </p> * * @author alevy */ public class DonutTestRunner { private final List<Node> nodeList; private final List<DonutInMemoryHashTableService> serviceList; private final LocalLocatorClientFactory clientFactory; private final List<DonutClient> clientList; private final PriorityQueue<DonutEvent> eventList; /** * @param ids * the ids of {@link Node}s that will be available to the Donut */ public DonutTestRunner(long... ids) { nodeList = new ArrayList<Node>(); serviceList = new ArrayList<DonutInMemoryHashTableService>(); eventList = new PriorityQueue<DonutEvent>(); clientList = new ArrayList<DonutClient>(); clientFactory = new LocalLocatorClientFactory(); for (int i = 0; i < ids.length; ++i) { createAndAddNode("node" + i, ids[i]); } } public int createAndAddNode(String name, long id) { Node node = new Node(name, 8080, new KeyId(id)); nodeList.add(node); DonutInMemoryHashTableService service = new DonutInMemoryHashTableService(); serviceList.add(service); NodeLocator nodeLocator = new NodeLocator(node, service, getClientFactory()); clientFactory.add(node.getTNode(), nodeLocator); clientList.add(new DonutClient(node, getClientFactory())); return clientList.size() - 1; } /** * Adds an event to the test * * @param milliseconds * the elapsed time in milliseconds, from the time {@link #run} is called, after * which this event will be triggered. * @return a {@link DonutEvent} which is used to add functionality to the event by calls to * {@link DonutEvent#join}, {@link DonutEvent#leave}, {@link DonutEvent#test}, etc'. */ public DonutEvent addEvent(int milliseconds) { DonutEvent donutEvent = new DonutEvent(milliseconds, this); getEventList().add(donutEvent); return donutEvent; } /** * Returns the {@link Node} referneced in this {@link DonutTestRunner} by the index specified. */ public Node node(int index) { return nodeList.get(index); } /** * Returns the {@link DonutInMemoryHashTableService} referneced in this {@link DonutTestRunner} * by the index specified. */ public DonutInMemoryHashTableService service(int index) { return serviceList.get(index); } protected LocalLocatorClientFactory getClientFactory() { return clientFactory; } public Iface iface(int index) throws RetryFailedException { return clientFactory.get(node(index).getTNode()); } protected DonutClient client(int index) { return clientList.get(index); } protected PriorityQueue<DonutEvent> getEventList() { return eventList; } /** * Runs the test. */ public void run() throws Exception { long start = System.currentTimeMillis(); while (!eventList.isEmpty()) { if (eventList.peek().getMilliseconds() <= (System.currentTimeMillis() - start)) { eventList.poll().run(); } } for (DonutClient client : clientList) { client.kill(); } } }