1 /* 2 * Copyright 2017 The gRPC Authors 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 17 package io.grpc.netty; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import java.util.concurrent.TimeUnit; 22 import org.junit.Test; 23 import org.junit.runner.RunWith; 24 import org.junit.runners.JUnit4; 25 26 /** Unit tests for {@link KeepAliveEnforcer}. */ 27 @RunWith(JUnit4.class) 28 public class KeepAliveEnforcerTest { 29 private static final int LARGE_NUMBER = KeepAliveEnforcer.MAX_PING_STRIKES * 5; 30 31 private FakeTicker ticker = new FakeTicker(); 32 33 @Test(expected = IllegalArgumentException.class) negativeTime()34 public void negativeTime() { 35 new KeepAliveEnforcer(true, -1, TimeUnit.NANOSECONDS); 36 } 37 38 @Test(expected = NullPointerException.class) nullTimeUnit()39 public void nullTimeUnit() { 40 new KeepAliveEnforcer(true, 1, null); 41 } 42 43 @Test permitLimitless()44 public void permitLimitless() { 45 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(true, 0, TimeUnit.NANOSECONDS, ticker); 46 for (int i = 0; i < LARGE_NUMBER; i++) { 47 assertThat(enforcer.pingAcceptable()).isTrue(); 48 } 49 enforcer.onTransportActive(); 50 for (int i = 0; i < LARGE_NUMBER; i++) { 51 assertThat(enforcer.pingAcceptable()).isTrue(); 52 } 53 enforcer.onTransportIdle(); 54 for (int i = 0; i < LARGE_NUMBER; i++) { 55 assertThat(enforcer.pingAcceptable()).isTrue(); 56 } 57 enforcer.resetCounters(); 58 for (int i = 0; i < LARGE_NUMBER; i++) { 59 assertThat(enforcer.pingAcceptable()).isTrue(); 60 } 61 } 62 63 @Test strikeOutBecauseNoOutstandingCalls()64 public void strikeOutBecauseNoOutstandingCalls() { 65 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(false, 0, TimeUnit.NANOSECONDS, ticker); 66 enforcer.onTransportIdle(); 67 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 68 assertThat(enforcer.pingAcceptable()).isTrue(); 69 } 70 assertThat(enforcer.pingAcceptable()).isFalse(); 71 } 72 73 @Test startsIdle()74 public void startsIdle() { 75 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(false, 0, TimeUnit.NANOSECONDS, ticker); 76 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 77 assertThat(enforcer.pingAcceptable()).isTrue(); 78 } 79 assertThat(enforcer.pingAcceptable()).isFalse(); 80 } 81 82 @Test strikeOutBecauseRateTooHighWhileActive()83 public void strikeOutBecauseRateTooHighWhileActive() { 84 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(true, 1, TimeUnit.NANOSECONDS, ticker); 85 enforcer.onTransportActive(); 86 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 87 assertThat(enforcer.pingAcceptable()).isTrue(); 88 } 89 assertThat(enforcer.pingAcceptable()).isFalse(); 90 } 91 92 @Test strikeOutBecauseRateTooHighWhileIdle()93 public void strikeOutBecauseRateTooHighWhileIdle() { 94 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(true, 1, TimeUnit.NANOSECONDS, ticker); 95 enforcer.onTransportIdle(); 96 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 97 assertThat(enforcer.pingAcceptable()).isTrue(); 98 } 99 assertThat(enforcer.pingAcceptable()).isFalse(); 100 } 101 102 @Test permitInRateWhileActive()103 public void permitInRateWhileActive() { 104 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(false, 1, TimeUnit.NANOSECONDS, ticker); 105 enforcer.onTransportActive(); 106 for (int i = 0; i < LARGE_NUMBER; i++) { 107 assertThat(enforcer.pingAcceptable()).isTrue(); 108 ticker.nanoTime += 1; 109 } 110 } 111 112 @Test permitInRateWhileIdle()113 public void permitInRateWhileIdle() { 114 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(true, 1, TimeUnit.NANOSECONDS, ticker); 115 enforcer.onTransportIdle(); 116 for (int i = 0; i < LARGE_NUMBER; i++) { 117 assertThat(enforcer.pingAcceptable()).isTrue(); 118 ticker.nanoTime += 1; 119 } 120 } 121 122 @Test implicitPermittedWhileIdle()123 public void implicitPermittedWhileIdle() { 124 KeepAliveEnforcer enforcer = new KeepAliveEnforcer( 125 false, KeepAliveEnforcer.IMPLICIT_PERMIT_TIME_NANOS * 10, TimeUnit.NANOSECONDS, ticker); 126 enforcer.onTransportIdle(); 127 for (int i = 0; i < LARGE_NUMBER; i++) { 128 assertThat(enforcer.pingAcceptable()).isTrue(); 129 ticker.nanoTime += KeepAliveEnforcer.IMPLICIT_PERMIT_TIME_NANOS; 130 } 131 } 132 133 @Test implicitOverridesWhileActive()134 public void implicitOverridesWhileActive() { 135 KeepAliveEnforcer enforcer = new KeepAliveEnforcer( 136 false, KeepAliveEnforcer.IMPLICIT_PERMIT_TIME_NANOS * 10, TimeUnit.NANOSECONDS, ticker); 137 enforcer.onTransportActive(); 138 for (int i = 0; i < LARGE_NUMBER; i++) { 139 assertThat(enforcer.pingAcceptable()).isTrue(); 140 ticker.nanoTime += KeepAliveEnforcer.IMPLICIT_PERMIT_TIME_NANOS; 141 } 142 } 143 144 @Test implicitOverridesWhileIdle()145 public void implicitOverridesWhileIdle() { 146 KeepAliveEnforcer enforcer = new KeepAliveEnforcer( 147 true, KeepAliveEnforcer.IMPLICIT_PERMIT_TIME_NANOS * 10, TimeUnit.NANOSECONDS, ticker); 148 enforcer.onTransportIdle(); 149 for (int i = 0; i < LARGE_NUMBER; i++) { 150 assertThat(enforcer.pingAcceptable()).isTrue(); 151 ticker.nanoTime += KeepAliveEnforcer.IMPLICIT_PERMIT_TIME_NANOS; 152 } 153 } 154 155 @Test permitsWhenTimeOverflows()156 public void permitsWhenTimeOverflows() { 157 ticker.nanoTime = Long.MAX_VALUE; 158 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(false, 1, TimeUnit.NANOSECONDS, ticker); 159 enforcer.onTransportActive(); 160 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 161 assertThat(enforcer.pingAcceptable()).isTrue(); 162 } 163 // Should have the maximum number of strikes now 164 ticker.nanoTime++; 165 assertThat(enforcer.pingAcceptable()).isTrue(); 166 } 167 168 @Test resetCounters_resetsStrikes()169 public void resetCounters_resetsStrikes() { 170 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(false, 1, TimeUnit.NANOSECONDS, ticker); 171 enforcer.onTransportActive(); 172 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 173 assertThat(enforcer.pingAcceptable()).isTrue(); 174 } 175 // Should have the maximum number of strikes now 176 enforcer.resetCounters(); 177 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 178 assertThat(enforcer.pingAcceptable()).isTrue(); 179 } 180 assertThat(enforcer.pingAcceptable()).isFalse(); 181 } 182 183 @Test resetCounters_resetsPingTime()184 public void resetCounters_resetsPingTime() { 185 KeepAliveEnforcer enforcer = new KeepAliveEnforcer(false, 1, TimeUnit.NANOSECONDS, ticker); 186 enforcer.onTransportActive(); 187 ticker.nanoTime += 1; 188 assertThat(enforcer.pingAcceptable()).isTrue(); 189 enforcer.resetCounters(); 190 // Should not cause a strike 191 assertThat(enforcer.pingAcceptable()).isTrue(); 192 for (int i = 0; i < KeepAliveEnforcer.MAX_PING_STRIKES; i++) { 193 assertThat(enforcer.pingAcceptable()).isTrue(); 194 } 195 } 196 197 @Test systemTickerIsSystemNanoTime()198 public void systemTickerIsSystemNanoTime() { 199 long before = System.nanoTime(); 200 long returned = KeepAliveEnforcer.SystemTicker.INSTANCE.nanoTime(); 201 long after = System.nanoTime(); 202 assertThat(returned).isAtLeast(before); 203 assertThat(returned).isAtMost(after); 204 } 205 206 private static class FakeTicker implements KeepAliveEnforcer.Ticker { 207 long nanoTime; 208 209 @Override nanoTime()210 public long nanoTime() { 211 return nanoTime; 212 } 213 } 214 } 215