/* * Copyright (c) 2011 LinkedIn, Inc * * 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 com.flaptor.indextank.search; import com.flaptor.indextank.IndexTankTestCase; import com.flaptor.indextank.query.Query; import com.flaptor.indextank.query.TermQuery; import com.flaptor.util.TestInfo; import com.google.common.collect.Lists; import java.util.Map; import java.util.concurrent.TimeUnit; import static com.flaptor.util.TestInfo.TestType.UNIT; public class TrafficLimitingSearcherTest extends IndexTankTestCase { private TrafficLimitingSearcher sleepSearcher; private TrafficLimitingSearcher fastSearcher; @Override protected void setUp() throws Exception { super.setUp(); this.sleepSearcher = new TrafficLimitingSearcher(new SleepingSearcher(3000), 3); this.fastSearcher = new TrafficLimitingSearcher(new SleepingSearcher(0), 3); } @Override protected void tearDown() throws Exception { super.tearDown(); } private void sleep(int millis) { try { TimeUnit.MILLISECONDS.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } @TestInfo(testType=UNIT) public void testQueueTooLong() { // start 3 that can run in parallel, and sleep to let them start new Thread(new RunSearch(sleepSearcher)).start(); sleep(100); new Thread(new RunSearch(sleepSearcher)).start(); sleep(100); new Thread(new RunSearch(sleepSearcher)).start(); sleep(100); // then start 3 to fill up the queue new Thread(new RunSearch(sleepSearcher)).start(); sleep(100); new Thread(new RunSearch(sleepSearcher)).start(); sleep(100); new Thread(new RunSearch(sleepSearcher)).start(); sleep(100); // now start one that should throw an exception because the queue is at max length try { final Query query = new Query(new TermQuery("text", "nada"), null, null); sleepSearcher.search(query, 0, 10, 0); fail("Should have thrown InterruptedException"); } catch (InterruptedException e) { System.out.println("InterruptedException thrown, success"); } } @TestInfo(testType=UNIT) public void testNonConcurrentSearching() throws InterruptedException { // make sure serial searches don't cause an InterruptedException for (int i = 0; i < 100; i++) { final Query query = new Query(new TermQuery("text", "nada"), null, null); fastSearcher.search(query, 0, 10, 0); } } @TestInfo(testType=UNIT) public void testConstructor() { new TrafficLimitingSearcher(sleepSearcher, 0); try { new TrafficLimitingSearcher(sleepSearcher, -1); fail("Constructor should not allow negative max queue length"); } catch (IllegalArgumentException iae) { // pass } } private static class RunSearch implements Runnable { final DocumentSearcher searcher; private RunSearch(DocumentSearcher searcher) { this.searcher = searcher; } @Override public void run() { try { final Query query = new Query(new TermQuery("text","hola"),null,null); searcher.search(query, 0, 10, 0); } catch (InterruptedException e) { e.printStackTrace(); } } } private class SleepingSearcher extends AbstractDocumentSearcher { private int sleepTime = 3000; private SleepingSearcher(int sleepTime) { this.sleepTime = sleepTime; } @Override public SearchResults search(Query query, int start, int limit, int scoringFunctionIndex, Map<String, String> extraParameters) throws InterruptedException { sleep(sleepTime); return new SearchResults(Lists.<SearchResult>newArrayList(), 0, null); } @Override public int countMatches(Query query) throws InterruptedException { sleep(sleepTime); return 0; } } }