69a023ad3158ebbbe0e1fd04c924d0358851a0d9
[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.Mockito;
27 import org.mockito.MockitoAnnotations;
28 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
29
30 public class TransactionRateLimitingCommitCallbackTest {
31
32     @Mock
33     public ActorContext actorContext;
34
35     @Mock
36     public DatastoreContext datastoreContext;
37
38     @Mock
39     public Timer commitTimer;
40
41     @Mock
42     private Timer.Context commitTimerContext;
43
44     @Mock
45     private Snapshot commitSnapshot;
46
47     @Before
48     public void setUp(){
49         MockitoAnnotations.initMocks(this);
50         doReturn(datastoreContext).when(actorContext).getDatastoreContext();
51         doReturn(30).when(datastoreContext).getShardTransactionCommitTimeoutInSeconds();
52         doReturn(commitTimer).when(actorContext).getOperationTimer("commit");
53         doReturn(commitTimerContext).when(commitTimer).time();
54         doReturn(commitSnapshot).when(commitTimer).getSnapshot();
55     }
56
57     @Test
58     public void testSuccess(){
59
60         for(int i=1;i<11;i++){
61             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
62             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
63             doReturn(TimeUnit.MILLISECONDS.toNanos(i) * 1D).when(commitSnapshot).getValue(i * 0.1);
64         }
65
66
67         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
68         commitCallback.run();
69         commitCallback.success();
70
71         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(292)));
72     }
73
74     @Test
75     public void testSuccessPercentileValueZero(){
76
77         for(int i=1;i<11;i++){
78             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
79             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
80             doReturn(TimeUnit.MILLISECONDS.toNanos(i) * 1D).when(commitSnapshot).getValue(i * 0.1);
81         }
82
83         doReturn(TimeUnit.MILLISECONDS.toNanos(0) * 1D).when(commitSnapshot).getValue(0.1);
84
85         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
86         commitCallback.run();
87         commitCallback.success();
88
89         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(192)));
90     }
91
92     @Test
93     public void testSuccessOnePercentileValueVeryHigh(){
94
95         for(int i=1;i<11;i++){
96             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
97             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
98             doReturn(TimeUnit.MILLISECONDS.toNanos(i) * 1D).when(commitSnapshot).getValue(i * 0.1);
99         }
100
101         // ten seconds
102         doReturn(TimeUnit.MILLISECONDS.toNanos(10000) * 1D).when(commitSnapshot).getValue(1.0);
103
104         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
105         commitCallback.run();
106         commitCallback.success();
107
108         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(282)));
109     }
110
111     @Test
112     public void testSuccessWithAllPercentileValueVeryHigh(){
113
114         for(int i=1;i<11;i++){
115             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
116             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
117             doReturn(TimeUnit.MILLISECONDS.toNanos(10000) * 1D).when(commitSnapshot).getValue(i * 0.1);
118         }
119
120         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
121         commitCallback.run();
122         commitCallback.success();
123
124         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(0)));
125     }
126
127     @Test
128     public void testSuccessWithRealPercentileValues(){
129
130         for(int i=1;i<11;i++){
131             // Keep on increasing the amount of time it takes to complete transaction for each tenth of a
132             // percentile. Essentially this would be 1ms for the 10th percentile, 2ms for 20th percentile and so on.
133             doReturn(TimeUnit.MILLISECONDS.toNanos(8) * 1D).when(commitSnapshot).getValue(i * 0.1);
134         }
135
136         doReturn(TimeUnit.MILLISECONDS.toNanos(20) * 1D).when(commitSnapshot).getValue( 0.7);
137         doReturn(TimeUnit.MILLISECONDS.toNanos(100) * 1D).when(commitSnapshot).getValue( 0.9);
138         doReturn(TimeUnit.MILLISECONDS.toNanos(200) * 1D).when(commitSnapshot).getValue( 1.0);
139
140         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
141         commitCallback.run();
142         commitCallback.success();
143
144         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(101)));
145     }
146
147
148     @Test
149     public void testSuccessWithoutRun(){
150         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
151
152         try {
153             commitCallback.success();
154             fail("Expected IllegalStateException");
155         } catch(IllegalStateException e){
156
157         }
158
159         verify(actorContext, never()).setTxCreationLimit(anyDouble());
160
161     }
162
163
164     @Test
165     public void testFailure(){
166         TransactionRateLimitingCallback commitCallback = new TransactionRateLimitingCallback(actorContext);
167         commitCallback.run();
168         commitCallback.failure();
169
170         verify(actorContext, never()).setTxCreationLimit(anyDouble());
171
172     }
173
174     @Test
175     public void testAdjustRateLimitForUnusedTransaction() {
176         doReturn(commitTimer).when(actorContext).getOperationTimer("one", "commit");
177         doReturn("one").when(actorContext).getDataStoreType();
178
179         Timer commitTimer2 = Mockito.mock(Timer.class);
180         Snapshot commitSnapshot2 = Mockito.mock(Snapshot.class);
181
182         doReturn(commitSnapshot2).when(commitTimer2).getSnapshot();
183
184         doReturn(commitTimer2).when(actorContext).getOperationTimer("two", "commit");
185
186         DatastoreContext.newBuilder().dataStoreType("one").build();
187         DatastoreContext.newBuilder().dataStoreType("two").build();
188
189         doReturn(TimeUnit.MICROSECONDS.toNanos(500) * 1D).when(commitSnapshot).getValue(1 * 0.1);
190
191         TransactionRateLimitingCallback.adjustRateLimitForUnusedTransaction(actorContext);
192
193         verify(actorContext, never()).setTxCreationLimit(anyDouble());
194
195         Mockito.reset(commitSnapshot);
196
197         TransactionRateLimitingCallback.adjustRateLimitForUnusedTransaction(actorContext);
198
199         verify(actorContext, never()).setTxCreationLimit(anyDouble());
200
201         System.out.println(""+TimeUnit.SECONDS.toNanos(30)/TimeUnit.MICROSECONDS.toNanos(100));
202
203         doReturn(TimeUnit.MICROSECONDS.toNanos(100) * 1D).when(commitSnapshot2).getValue(1 * 0.1);
204
205         TransactionRateLimitingCallback.adjustRateLimitForUnusedTransaction(actorContext);
206
207         verify(actorContext).setTxCreationLimit(Matchers.doubleThat(approximately(1000)));
208     }
209
210     public Matcher<Double> approximately(final double val){
211         return new BaseMatcher<Double>() {
212             @Override
213             public boolean matches(Object o) {
214                 Double aDouble = (Double) o;
215                 return aDouble >= val && aDouble <= val+1;
216             }
217
218             @Override
219             public void describeTo(Description description) {
220                 description.appendText("> " + val +" < " + (val+1));
221             }
222         };
223     }
224
225
226 }