Home | History | Annotate | Download | only in okhttp
      1 package com.squareup.okhttp;
      2 
      3 import com.squareup.okhttp.Call.AsyncCall;
      4 import java.util.ArrayList;
      5 import java.util.Arrays;
      6 import java.util.Iterator;
      7 import java.util.List;
      8 import java.util.concurrent.AbstractExecutorService;
      9 import java.util.concurrent.TimeUnit;
     10 import org.junit.Before;
     11 import org.junit.Test;
     12 
     13 import static org.junit.Assert.assertEquals;
     14 import static org.junit.Assert.fail;
     15 
     16 public final class DispatcherTest {
     17   RecordingExecutor executor = new RecordingExecutor();
     18   RecordingCallback callback = new RecordingCallback();
     19   Dispatcher dispatcher = new Dispatcher(executor);
     20   OkHttpClient client = new OkHttpClient().setDispatcher(dispatcher);
     21 
     22   @Before public void setUp() throws Exception {
     23     dispatcher.setMaxRequests(20);
     24     dispatcher.setMaxRequestsPerHost(10);
     25   }
     26 
     27   @Test public void maxRequestsZero() throws Exception {
     28     try {
     29       dispatcher.setMaxRequests(0);
     30       fail();
     31     } catch (IllegalArgumentException expected) {
     32     }
     33   }
     34 
     35   @Test public void maxPerHostZero() throws Exception {
     36     try {
     37       dispatcher.setMaxRequestsPerHost(0);
     38       fail();
     39     } catch (IllegalArgumentException expected) {
     40     }
     41   }
     42 
     43   @Test public void enqueuedJobsRunImmediately() throws Exception {
     44     client.newCall(newRequest("http://a/1")).enqueue(callback);
     45     executor.assertJobs("http://a/1");
     46   }
     47 
     48   @Test public void maxRequestsEnforced() throws Exception {
     49     dispatcher.setMaxRequests(3);
     50     client.newCall(newRequest("http://a/1")).enqueue(callback);
     51     client.newCall(newRequest("http://a/2")).enqueue(callback);
     52     client.newCall(newRequest("http://b/1")).enqueue(callback);
     53     client.newCall(newRequest("http://b/2")).enqueue(callback);
     54     executor.assertJobs("http://a/1", "http://a/2", "http://b/1");
     55   }
     56 
     57   @Test public void maxPerHostEnforced() throws Exception {
     58     dispatcher.setMaxRequestsPerHost(2);
     59     client.newCall(newRequest("http://a/1")).enqueue(callback);
     60     client.newCall(newRequest("http://a/2")).enqueue(callback);
     61     client.newCall(newRequest("http://a/3")).enqueue(callback);
     62     executor.assertJobs("http://a/1", "http://a/2");
     63   }
     64 
     65   @Test public void increasingMaxRequestsPromotesJobsImmediately() throws Exception {
     66     dispatcher.setMaxRequests(2);
     67     client.newCall(newRequest("http://a/1")).enqueue(callback);
     68     client.newCall(newRequest("http://b/1")).enqueue(callback);
     69     client.newCall(newRequest("http://c/1")).enqueue(callback);
     70     client.newCall(newRequest("http://a/2")).enqueue(callback);
     71     client.newCall(newRequest("http://b/2")).enqueue(callback);
     72     dispatcher.setMaxRequests(4);
     73     executor.assertJobs("http://a/1", "http://b/1", "http://c/1", "http://a/2");
     74   }
     75 
     76   @Test public void increasingMaxPerHostPromotesJobsImmediately() throws Exception {
     77     dispatcher.setMaxRequestsPerHost(2);
     78     client.newCall(newRequest("http://a/1")).enqueue(callback);
     79     client.newCall(newRequest("http://a/2")).enqueue(callback);
     80     client.newCall(newRequest("http://a/3")).enqueue(callback);
     81     client.newCall(newRequest("http://a/4")).enqueue(callback);
     82     client.newCall(newRequest("http://a/5")).enqueue(callback);
     83     dispatcher.setMaxRequestsPerHost(4);
     84     executor.assertJobs("http://a/1", "http://a/2", "http://a/3", "http://a/4");
     85   }
     86 
     87   @Test public void oldJobFinishesNewJobCanRunDifferentHost() throws Exception {
     88     dispatcher.setMaxRequests(1);
     89     client.newCall(newRequest("http://a/1")).enqueue(callback);
     90     client.newCall(newRequest("http://b/1")).enqueue(callback);
     91     executor.finishJob("http://a/1");
     92     executor.assertJobs("http://b/1");
     93   }
     94 
     95   @Test public void oldJobFinishesNewJobWithSameHostStarts() throws Exception {
     96     dispatcher.setMaxRequests(2);
     97     dispatcher.setMaxRequestsPerHost(1);
     98     client.newCall(newRequest("http://a/1")).enqueue(callback);
     99     client.newCall(newRequest("http://b/1")).enqueue(callback);
    100     client.newCall(newRequest("http://b/2")).enqueue(callback);
    101     client.newCall(newRequest("http://a/2")).enqueue(callback);
    102     executor.finishJob("http://a/1");
    103     executor.assertJobs("http://b/1", "http://a/2");
    104   }
    105 
    106   @Test public void oldJobFinishesNewJobCantRunDueToHostLimit() throws Exception {
    107     dispatcher.setMaxRequestsPerHost(1);
    108     client.newCall(newRequest("http://a/1")).enqueue(callback);
    109     client.newCall(newRequest("http://b/1")).enqueue(callback);
    110     client.newCall(newRequest("http://a/2")).enqueue(callback);
    111     executor.finishJob("http://b/1");
    112     executor.assertJobs("http://a/1");
    113   }
    114 
    115   @Test public void cancelingRunningJobTakesNoEffectUntilJobFinishes() throws Exception {
    116     dispatcher.setMaxRequests(1);
    117     client.newCall(newRequest("http://a/1", "tag1")).enqueue(callback);
    118     client.newCall(newRequest("http://a/2")).enqueue(callback);
    119     dispatcher.cancel("tag1");
    120     executor.assertJobs("http://a/1");
    121     executor.finishJob("http://a/1");
    122     executor.assertJobs("http://a/2");
    123   }
    124 
    125   class RecordingExecutor extends AbstractExecutorService {
    126     private List<AsyncCall> calls = new ArrayList<>();
    127 
    128     @Override public void execute(Runnable command) {
    129       calls.add((AsyncCall) command);
    130     }
    131 
    132     public void assertJobs(String... expectedUrls) {
    133       List<String> actualUrls = new ArrayList<>();
    134       for (AsyncCall call : calls) {
    135         actualUrls.add(call.request().urlString());
    136       }
    137       assertEquals(Arrays.asList(expectedUrls), actualUrls);
    138     }
    139 
    140     public void finishJob(String url) {
    141       for (Iterator<AsyncCall> i = calls.iterator(); i.hasNext(); ) {
    142         AsyncCall call = i.next();
    143         if (call.request().urlString().equals(url)) {
    144           i.remove();
    145           dispatcher.finished(call);
    146           return;
    147         }
    148       }
    149       throw new AssertionError("No such job: " + url);
    150     }
    151 
    152     @Override public void shutdown() {
    153       throw new UnsupportedOperationException();
    154     }
    155 
    156     @Override public List<Runnable> shutdownNow() {
    157       throw new UnsupportedOperationException();
    158     }
    159 
    160     @Override public boolean isShutdown() {
    161       throw new UnsupportedOperationException();
    162     }
    163 
    164     @Override public boolean isTerminated() {
    165       throw new UnsupportedOperationException();
    166     }
    167 
    168     @Override public boolean awaitTermination(long timeout, TimeUnit unit)
    169         throws InterruptedException {
    170       throw new UnsupportedOperationException();
    171     }
    172   }
    173 
    174   private Request newRequest(String url) {
    175     return new Request.Builder().url(url).build();
    176   }
    177 
    178   private Request newRequest(String url, String tag) {
    179     return new Request.Builder().url(url).tag(tag).build();
    180   }
    181 }
    182