• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockitousage.bugs;
6 
7 import static org.junit.Assert.fail;
8 
9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.Executors;
11 import java.util.concurrent.TimeUnit;
12 import java.util.concurrent.atomic.AtomicInteger;
13 
14 import org.junit.Test;
15 import org.mockito.Mockito;
16 import org.mockito.invocation.InvocationOnMock;
17 import org.mockito.stubbing.Answer;
18 
19 // see bug 190
20 public class ShouldNotDeadlockAnswerExecutionTest {
21 
22     @Test
failIfMockIsSharedBetweenThreads()23     public void failIfMockIsSharedBetweenThreads() throws Exception {
24         Service service = Mockito.mock(Service.class);
25         ExecutorService threads = Executors.newCachedThreadPool();
26         AtomicInteger counter = new AtomicInteger(2);
27 
28         // registed answer on verySlowMethod
29 
30         Mockito.when(service.verySlowMethod()).thenAnswer(new LockingAnswer(counter));
31 
32         // execute verySlowMethod twice in separate threads
33 
34         threads.execute(new ServiceRunner(service));
35         threads.execute(new ServiceRunner(service));
36 
37         // waiting for threads to finish
38 
39         threads.shutdown();
40 
41         if (!threads.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
42             // threads were timed-out
43             fail();
44         }
45     }
46 
47     @Test
successIfEveryThreadHasItsOwnMock()48     public void successIfEveryThreadHasItsOwnMock() throws Exception {
49         Service service1 = Mockito.mock(Service.class);
50         Service service2 = Mockito.mock(Service.class);
51         ExecutorService threads = Executors.newCachedThreadPool();
52         AtomicInteger counter = new AtomicInteger(2);
53 
54         // registed answer on verySlowMethod
55 
56         Mockito.when(service1.verySlowMethod()).thenAnswer(new LockingAnswer(counter));
57         Mockito.when(service2.verySlowMethod()).thenAnswer(new LockingAnswer(counter));
58 
59         // execute verySlowMethod twice in separate threads
60 
61         threads.execute(new ServiceRunner(service1));
62         threads.execute(new ServiceRunner(service2));
63 
64         // waiting for threads to finish
65 
66         threads.shutdown();
67 
68         if (!threads.awaitTermination(500, TimeUnit.MILLISECONDS)) {
69             // threads were timed-out
70             fail();
71         }
72     }
73 
74     static class LockingAnswer implements Answer<String> {
75 
76         private AtomicInteger counter;
77 
LockingAnswer(AtomicInteger counter)78         public LockingAnswer(AtomicInteger counter) {
79             this.counter = counter;
80         }
81 
82         /**
83          * Decrement counter and wait until counter has value 0
84          */
answer(InvocationOnMock invocation)85         public String answer(InvocationOnMock invocation) throws Throwable {
86             counter.decrementAndGet();
87 
88             while (counter.get() != 0) {
89                 Thread.sleep(10);
90             }
91 
92             return null;
93         }
94     }
95 
96     static class ServiceRunner implements Runnable {
97 
98         private Service service;
99 
ServiceRunner(Service service)100         public ServiceRunner(Service service) {
101             this.service = service;
102         }
103 
run()104         public void run() {
105             service.verySlowMethod();
106         }
107     }
108 
109     interface Service {
110 
verySlowMethod()111         String verySlowMethod();
112     }
113 }
114