package book.example.threading.executor;
import book.example.common.searching.AuctionDescription;
import book.example.common.searching.AuctionHouse;
import book.example.common.searching.StubAuctionHouse;
import book.example.common.searching.async.AuctionSearchConsumer;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.States;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.concurrent.DeterministicExecutor;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
/**
* Note: deterministic scheduler won't catch the synchronisation error in the
* class under test. So, this makes it easier to test the functionality
* of the class but you still need to stress test the synchronisation.
*/
@RunWith(JMock.class)
public class AuctionSearch_v2_Tests {
final Mockery context = new JUnit4Mockery();
final DeterministicExecutor executor = new DeterministicExecutor();
final StubAuctionHouse houseA = new StubAuctionHouse("houseA");
final StubAuctionHouse houseB = new StubAuctionHouse("houseB");
List<AuctionDescription> resultsFromA = asList(auction(houseA, "1"));
List<AuctionDescription> resultsFromB = asList(auction(houseB, "2"));
;
final AuctionSearchConsumer consumer = context.mock(AuctionSearchConsumer.class);
AuctionSearch_v3 search = new AuctionSearch_v3(executor, houses(houseA, houseB), consumer);
@Test
public void
searchesAllAuctionHouses() throws Exception {
final Set<String> keywords = set("sheep", "cheese");
houseA.willReturnSearchResults(keywords, resultsFromA);
houseB.willReturnSearchResults(keywords, resultsFromB);
context.checking(new Expectations() {{
final States searching = context.states("searching");
oneOf(consumer).auctionSearchFound(resultsFromA);
when(searching.isNot("done"));
oneOf(consumer).auctionSearchFound(resultsFromB);
when(searching.isNot("done"));
oneOf(consumer).auctionSearchFinished();
then(searching.is("done"));
}});
search.search(keywords);
executor.runUntilIdle();
}
@Test
public void doesNotAnnounceEmptySearchResults() throws Exception {
final Set<String> keywords = set("keywords");
houseA.willReturnSearchResults(keywords, resultsFromA);
houseB.willReturnSearchResults(keywords, noResults());
context.checking(new Expectations() {{
oneOf(consumer).auctionSearchFound(resultsFromA);
oneOf(consumer).auctionSearchFinished();
}});
search.search(keywords);
executor.runUntilIdle();
}
private List<AuctionDescription> noResults() {
return emptyList();
}
private List<AuctionHouse> houses(AuctionHouse... houses) {
return asList(houses);
}
private AuctionDescription auction(AuctionHouse house, String id) {
return new AuctionDescription(house, id, "test auction " + id);
}
private Set<String> set(String... strings) {
return new HashSet<String>(Arrays.asList(strings));
}
}