1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.verification;
6 
7 import org.mockito.exceptions.base.MockitoAssertionError;
8 import org.mockito.internal.util.Timer;
9 import org.mockito.internal.verification.api.VerificationData;
10 import org.mockito.verification.VerificationMode;
11 
12 /**
13  * Verifies that another verification mode (the delegate) is satisfied within a certain timeframe
14  * (before timeoutMillis has passed, measured from the call to verify()), and either returns immediately
15  * once it does, or waits until it is definitely satisfied once the full time has passed.
16  */
17 public class VerificationOverTimeImpl implements VerificationMode {
18 
19     private final long pollingPeriodMillis;
20     private final VerificationMode delegate;
21     private final boolean returnOnSuccess;
22     private final Timer timer;
23 
24     /**
25      * Create this verification mode, to be used to verify invocation ongoing data later.
26      *
27      * @param pollingPeriodMillis The frequency to poll delegate.verify(), to check whether the delegate has been satisfied
28      * @param durationMillis The max time to wait (in millis) for the delegate verification mode to be satisfied
29      * @param delegate The verification mode to delegate overall success or failure to
30      * @param returnOnSuccess Whether to immediately return successfully once the delegate is satisfied (as in
31      *                        {@link org.mockito.verification.VerificationWithTimeout}, or to only return once
32      *                        the delegate is satisfied and the full duration has passed (as in
33      *                        {@link org.mockito.verification.VerificationAfterDelay}).
34      */
VerificationOverTimeImpl(long pollingPeriodMillis, long durationMillis, VerificationMode delegate, boolean returnOnSuccess)35     public VerificationOverTimeImpl(long pollingPeriodMillis, long durationMillis, VerificationMode delegate, boolean returnOnSuccess) {
36         this(pollingPeriodMillis, delegate, returnOnSuccess, new Timer(durationMillis));
37     }
38 
39     /**
40      * Create this verification mode, to be used to verify invocation ongoing data later.
41      *
42      * @param pollingPeriodMillis The frequency to poll delegate.verify(), to check whether the delegate has been satisfied
43      * @param delegate The verification mode to delegate overall success or failure to
44      * @param returnOnSuccess Whether to immediately return successfully once the delegate is satisfied (as in
45      *                        {@link org.mockito.verification.VerificationWithTimeout}, or to only return once
46      *                        the delegate is satisfied and the full duration has passed (as in
47      *                        {@link org.mockito.verification.VerificationAfterDelay}).
48      * @param timer Checker of whether the duration of the verification is still acceptable
49      */
VerificationOverTimeImpl(long pollingPeriodMillis, VerificationMode delegate, boolean returnOnSuccess, Timer timer)50     public VerificationOverTimeImpl(long pollingPeriodMillis, VerificationMode delegate, boolean returnOnSuccess, Timer timer) {
51         this.pollingPeriodMillis = pollingPeriodMillis;
52         this.delegate = delegate;
53         this.returnOnSuccess = returnOnSuccess;
54         this.timer = timer;
55     }
56 
57     /**
58      * Verify the given ongoing verification data, and confirm that it satisfies the delegate verification mode
59      * before the full duration has passed.
60      *
61      * In practice, this polls the delegate verification mode until it is satisfied. If it is not satisfied once
62      * the full duration has passed, the last error returned by the delegate verification mode will be thrown
63      * here in turn. This may be thrown early if the delegate is unsatisfied and the verification mode is known
64      * to never recover from this situation (e.g. {@link AtMost}).
65      *
66      * If it is satisfied before the full duration has passed, behaviour is dependent on the returnOnSuccess parameter
67      * given in the constructor. If true, this verification mode is immediately satisfied once the delegate is. If
68      * false, this verification mode is not satisfied until the delegate is satisfied and the full time has passed.
69      *
70      * @throws MockitoAssertionError if the delegate verification mode does not succeed before the timeout
71      */
verify(VerificationData data)72     public void verify(VerificationData data) {
73         AssertionError error = null;
74 
75         timer.start();
76         while (timer.isCounting()) {
77             try {
78                 delegate.verify(data);
79 
80                 if (returnOnSuccess) {
81                     return;
82                 } else {
83                     error = null;
84                 }
85             } catch (MockitoAssertionError e) {
86                 error = handleVerifyException(e);
87             }
88             catch (AssertionError e) {
89                 error = handleVerifyException(e);
90             }
91         }
92 
93         if (error != null) {
94             throw error;
95         }
96     }
97 
handleVerifyException(AssertionError e)98     private AssertionError handleVerifyException(AssertionError e) {
99         if (canRecoverFromFailure(delegate)) {
100             sleep(pollingPeriodMillis);
101             return e;
102         } else {
103             throw e;
104         }
105     }
106 
canRecoverFromFailure(VerificationMode verificationMode)107     protected boolean canRecoverFromFailure(VerificationMode verificationMode) {
108         return !(verificationMode instanceof AtMost || verificationMode instanceof NoMoreInteractions);
109     }
110 
copyWithVerificationMode(VerificationMode verificationMode)111     public VerificationOverTimeImpl copyWithVerificationMode(VerificationMode verificationMode) {
112         return new VerificationOverTimeImpl(pollingPeriodMillis, timer.duration(), verificationMode, returnOnSuccess);
113     }
114 
sleep(long sleep)115     private void sleep(long sleep) {
116         try {
117             Thread.sleep(sleep);
118         } catch (InterruptedException ie) {
119             throw new RuntimeException("Thread sleep has been interrupted", ie);
120         }
121     }
122 
123     @Override
description(String description)124     public VerificationMode description(String description) {
125         return VerificationModeFactory.description(this, description);
126     }
127 
isReturnOnSuccess()128     public boolean isReturnOnSuccess() {
129         return returnOnSuccess;
130     }
131 
getPollingPeriodMillis()132     public long getPollingPeriodMillis() {
133         return pollingPeriodMillis;
134     }
135 
getTimer()136     public Timer getTimer() {
137         return timer;
138     }
139 
getDelegate()140     public VerificationMode getDelegate() {
141         return delegate;
142     }
143 }
144