package edu.harvard.econcs.turkserver.mturk; import static org.junit.Assert.*; import java.util.Collections; import java.util.HashSet; import java.util.Set; import net.andrewmao.math.RandomSelection; import org.junit.After; import org.junit.Before; import org.junit.Test; import edu.harvard.econcs.turkserver.mturk.TurkHITController.CreateTask; import edu.harvard.econcs.turkserver.schema.Session; import edu.harvard.econcs.turkserver.server.mysql.MockDataTracker; public class TurkHITControllerTest { @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testAdaptiveMath() { int num = 400; int min = 10; int max = 50; double overhead = 0.15; CreateTask someTask = new CreateTask(num, min, max, 0, 0, overhead); for( int i = 0; i <= 400; i++ ) { int target = TurkHITController.getAdaptiveTarget(i, someTask); assertTrue(target >= i + min); assertTrue(target <= i + max); assertTrue(target == i + min || target == i + max || target == (int) Math.round(i * (1+overhead) ) ); } } @Test public void testHITCreation() { MockDataTracker mockTracker = new MockDataTracker(); MockRequesterService mockReq = new MockRequesterService(); TurkHITController hits = new TurkHITController(mockReq, mockTracker); Thread runner = new Thread(hits); runner.start(); int num = 200; int min = 10; int max = 50; int delay = 2; int maxdelay = 1000; double overhead = 0.1; Set<String> unusedHITs = Collections.synchronizedSet(new HashSet<String>()); Set<String> takenHITs = new HashSet<String>(); Set<String> completedHITs = new HashSet<String>(); mockReq.setCreationSet(unusedHITs); hits.postBatchHITs(num, min, max, delay, maxdelay, overhead); // Randomly accept, return, and complete HITs do { double action = Math.random(); /* * TODO: this is not updating the mappings in mocktracker * but doesn't matter for this */ if( action < 0.4 ) { // take a random HIT String hit = RandomSelection.selectRandom(unusedHITs); if( hit == null ) continue; unusedHITs.remove(hit); takenHITs.add(hit); // Let's just make sure it's been stored try { Thread.sleep(delay); } catch (InterruptedException e) {} Session s = mockTracker.getStoredSessionInfo(hit); synchronized(mockTracker) { s.setWorkerId("Worker for " + hit); } } else if (action > 0.6) { // complete a random HIT String hit = RandomSelection.selectRandom(takenHITs); if( hit == null ) continue; takenHITs.remove(hit); completedHITs.add(hit); Session s = mockTracker.getStoredSessionInfo(hit); synchronized(mockTracker) { s.setInactivePercent(0d); } } else { // return a random HIT String hit = RandomSelection.selectRandom(takenHITs); if( hit == null ) continue; takenHITs.remove(hit); unusedHITs.add(hit); Session s = mockTracker.getStoredSessionInfo(hit); synchronized(mockTracker) { s.setWorkerId(null); } } try { Thread.sleep(4*delay); } catch (InterruptedException e) {} // Check that hit posting thread is being proper int unusedSize = unusedHITs.size(); int takenSize = takenHITs.size(); int completedSize = completedHITs.size(); int createdHITs = unusedSize + takenSize + completedSize; int acceptedHITs = takenSize + completedSize; System.out.printf("created: %d, accepted/completed: %d\n", createdHITs, acceptedHITs); assertTrue(createdHITs >= acceptedHITs + min || createdHITs <= min); assertTrue(createdHITs <= acceptedHITs + max); assertTrue( createdHITs == acceptedHITs + min || createdHITs <= min || createdHITs <= acceptedHITs + max || createdHITs >= (int) Math.round(acceptedHITs * (1+overhead) ) // Inequality due to returned HITs ); } while ( completedHITs.size() < num ); // Verify that disabled HITs are what is left in unused/taken Set<String> disabledHITs = Collections.synchronizedSet(new HashSet<String>()); mockReq.setDisableSet(disabledHITs); hits.disableAndShutdown(); try { runner.join(); } catch (InterruptedException e) { e.printStackTrace(); } unusedHITs.addAll(takenHITs); // Combine two remaining sets together assertTrue(unusedHITs.containsAll(disabledHITs)); assertTrue(disabledHITs.containsAll(unusedHITs)); } }