BUG 2762 : Compute rate limit based on a more lenient algorithm
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / TransactionRateLimitingCommitCallbackTest.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.cluster.datastore;
10
11 import static org.junit.Assert.fail;
12 import static org.mockito.Matchers.anyDouble;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.never;
15 import static org.mockito.Mockito.verify;
16 import com.codahale.metrics.Snapshot;
17 import com.codahale.metrics.Timer;
18 import java.util.concurrent.TimeUnit;
19 import org.hamcrest.BaseMatcher;
20 import org.hamcrest.Description;
21 import org.hamcrest.Matcher;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.mockito.Matchers;
25 import org.mockito.Mock;
26 import org.mockito.MockitoAnnotations;
27 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
28
29 public class TransactionRateLimitingCommitCallbackTest {
30
31     @Mock
32     public ActorContext actorContext;
33
34     @Mock
35     public DatastoreContext datastoreContext;
36
37     @Mock
38     public Timer commitTimer;
39
40     @Mock
41     private Timer.Context commitTimerContext;
42
43     @Mock
44     private Snapshot commitSnapshot;
45
46     @Before
47     public void setUp(){
48         MockitoAnnotations.initMocks(this);
49         doReturn(datastoreContext).when(actorContext).getDatastoreContext();
50         doReturn(30).when(datastoreContext).getShardTransactionCommitTimeoutInSeconds();
51         doReturn(commitTimer).when(actorContext).getOperationTimer("commit");
52         doReturn(commitTimerContext).when(commitTimer).time();
53         doReturn(commitSnapshot).when(commitTimer).getSnapshot();
54     }
55
56     @Test
57     public void testSuccess(){
58
59         for(int i=1;i<11;i++){
60             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
61             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
62             doReturn(TimeUnit.MILLISECONDS.toNanos(i) * 1D).when(commitSnapshot).getValue(i * 0.1);
63         }
64
65
66         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
67         commitCallback.run();
68         commitCallback.success();
69
70         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(292)));
71
72         doReturn(TimeUnit.MILLISECONDS.toNanos(0) * 1D).when(commitSnapshot).getValue(0.1);
73
74         commitCallback = new TransactionRateLimitingCallback(actorContext);
75         commitCallback.run();
76         commitCallback.success();
77
78         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(292)));
79     }
80
81     @Test
82     public void testSuccessPercentileValueZero(){
83
84         for(int i=1;i<11;i++){
85             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
86             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
87             doReturn(TimeUnit.MILLISECONDS.toNanos(i) * 1D).when(commitSnapshot).getValue(i * 0.1);
88         }
89
90         doReturn(TimeUnit.MILLISECONDS.toNanos(0) * 1D).when(commitSnapshot).getValue(0.1);
91
92         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
93         commitCallback.run();
94         commitCallback.success();
95
96         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(192)));
97     }
98
99     @Test
100     public void testSuccessOnePercentileValueVeryHigh(){
101
102         for(int i=1;i<11;i++){
103             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
104             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
105             doReturn(TimeUnit.MILLISECONDS.toNanos(i) * 1D).when(commitSnapshot).getValue(i * 0.1);
106         }
107
108         // ten seconds
109         doReturn(TimeUnit.MILLISECONDS.toNanos(10000) * 1D).when(commitSnapshot).getValue(1.0);
110
111         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
112         commitCallback.run();
113         commitCallback.success();
114
115         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(282)));
116     }
117
118     @Test
119     public void testSuccessWithAllPercentileValueVeryHigh(){
120
121         for(int i=1;i<11;i++){
122             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
123             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
124             doReturn(TimeUnit.MILLISECONDS.toNanos(10000) * 1D).when(commitSnapshot).getValue(i * 0.1);
125         }
126
127         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
128         commitCallback.run();
129         commitCallback.success();
130
131         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(0)));
132     }
133
134     @Test
135     public void testSuccessWithRealPercentileValues(){
136
137         for(int i=1;i<11;i++){
138             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
139             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
140             doReturn(TimeUnit.MILLISECONDS.toNanos(8) * 1D).when(commitSnapshot).getValue(i * 0.1);
141         }
142
143         doReturn(TimeUnit.MILLISECONDS.toNanos(20) * 1D).when(commitSnapshot).getValue( 0.7);
144         doReturn(TimeUnit.MILLISECONDS.toNanos(100) * 1D).when(commitSnapshot).getValue( 0.9);
145         doReturn(TimeUnit.MILLISECONDS.toNanos(200) * 1D).when(commitSnapshot).getValue( 1.0);
146
147         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
148         commitCallback.run();
149         commitCallback.success();
150
151         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(101)));
152     }
153
154
155     @Test
156     public void testSuccessWithoutRun(){
157         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
158
159         try {
160             commitCallback.success();
161             fail("Expected IllegalStateException");
162         } catch(IllegalStateException e){
163
164         }
165
166         verify(actorContext, never()).setTxCreationLimit(anyDouble());
167
168     }
169
170
171     @Test
172     public void testFailure(){
173         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
174         commitCallback.run();
175         commitCallback.failure();
176
177         verify(actorContext, never()).setTxCreationLimit(anyDouble());
178
179     }
180
181     public Matcher<Double> approximately(final double val){
182         return new BaseMatcher<Double>() {
183             @Override
184             public boolean matches(Object o) {
185                 Double aDouble = (Double) o;
186                 return aDouble > val && aDouble < val+1;
187             }
188
189             @Override
190             public void describeTo(Description description) {
191
192             }
193         };
194     }
195
196
197 }