1 /* 2 * Copyright (C) 2014 Google, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package dagger.internal; 17 18 import com.google.common.collect.Lists; 19 import com.google.common.collect.Sets; 20 import com.google.common.util.concurrent.Uninterruptibles; 21 import dagger.Lazy; 22 import java.util.List; 23 import java.util.Set; 24 import java.util.concurrent.Callable; 25 import java.util.concurrent.CountDownLatch; 26 import java.util.concurrent.ExecutorService; 27 import java.util.concurrent.Executors; 28 import java.util.concurrent.Future; 29 import java.util.concurrent.atomic.AtomicInteger; 30 import javax.inject.Provider; 31 import org.junit.Ignore; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.JUnit4; 35 36 import static com.google.common.truth.Truth.assert_; 37 import static org.junit.Assert.fail; 38 39 @RunWith(JUnit4.class) 40 public class DoubleCheckLazyTest { 41 @Test public void get() throws Exception { 42 int numThreads = 10; 43 ExecutorService executor = Executors.newFixedThreadPool(numThreads); 44 45 final CountDownLatch latch = new CountDownLatch(numThreads); 46 LatchedProvider provider = new LatchedProvider(latch); 47 final Lazy<Object> lazy = DoubleCheckLazy.create(provider); 48 49 List<Callable<Object>> tasks = Lists.newArrayListWithCapacity(numThreads); 50 for (int i = 0; i < numThreads; i++) { 51 tasks.add(new Callable<Object>() { 52 @Override public Object call() throws Exception { 53 latch.countDown(); 54 return lazy.get(); 55 } 56 }); 57 } 58 59 List<Future<Object>> futures = executor.invokeAll(tasks); 60 61 assert_().that(provider.provisions.get()).isEqualTo(1); 62 Set<Object> results = Sets.newIdentityHashSet(); 63 for (Future<Object> future : futures) { 64 results.add(future.get()); 65 } 66 assert_().that(results.size()).isEqualTo(1); 67 } 68 69 // TODO(gak): reenable this test once we can ensure that factories are no longer providing null 70 @Ignore @Test public void get_null() { 71 Lazy<Object> lazy = DoubleCheckLazy.create(new Provider<Object> () { 72 @Override public Object get() { 73 return null; 74 } 75 }); 76 try { 77 lazy.get(); 78 fail(); 79 } catch (NullPointerException expected) {} 80 } 81 82 private static class LatchedProvider implements Provider<Object> { 83 final AtomicInteger provisions; 84 final CountDownLatch latch; 85 86 LatchedProvider(CountDownLatch latch) { 87 this.latch = latch; 88 this.provisions = new AtomicInteger(); 89 } 90 91 @Override 92 public Object get() { 93 if (latch != null) { 94 Uninterruptibles.awaitUninterruptibly(latch); 95 } 96 provisions.incrementAndGet(); 97 return new Object(); 98 } 99 } 100 } 101