Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright 2018 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.testing;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 import static org.junit.Assert.assertSame;
     21 import static org.junit.Assert.assertTrue;
     22 import static org.mockito.AdditionalAnswers.delegatesTo;
     23 import static org.mockito.Matchers.any;
     24 import static org.mockito.Matchers.anyLong;
     25 import static org.mockito.Mockito.doReturn;
     26 import static org.mockito.Mockito.doThrow;
     27 import static org.mockito.Mockito.inOrder;
     28 import static org.mockito.Mockito.mock;
     29 import static org.mockito.Mockito.never;
     30 import static org.mockito.Mockito.verify;
     31 import static org.mockito.Mockito.verifyNoMoreInteractions;
     32 
     33 import io.grpc.ManagedChannel;
     34 import io.grpc.Server;
     35 import io.grpc.internal.FakeClock;
     36 import io.grpc.testing.GrpcCleanupRule.Resource;
     37 import java.util.concurrent.TimeUnit;
     38 import org.junit.Rule;
     39 import org.junit.Test;
     40 import org.junit.rules.ExpectedException;
     41 import org.junit.runner.RunWith;
     42 import org.junit.runners.JUnit4;
     43 import org.junit.runners.model.MultipleFailureException;
     44 import org.junit.runners.model.Statement;
     45 import org.mockito.InOrder;
     46 
     47 /**
     48  * Unit tests for {@link GrpcCleanupRule}.
     49  */
     50 @RunWith(JUnit4.class)
     51 public class GrpcCleanupRuleTest {
     52   public static final FakeClock fakeClock = new FakeClock();
     53 
     54   @Rule
     55   public ExpectedException thrown = ExpectedException.none();
     56 
     57   @Test
     58   public void registerChannelReturnSameChannel() {
     59     ManagedChannel channel = mock(ManagedChannel.class);
     60     assertSame(channel, new GrpcCleanupRule().register(channel));
     61   }
     62 
     63   @Test
     64   public void registerServerReturnSameServer() {
     65     Server server = mock(Server.class);
     66     assertSame(server, new GrpcCleanupRule().register(server));
     67   }
     68 
     69   @Test
     70   public void registerNullChannelThrowsNpe() {
     71     ManagedChannel channel = null;
     72     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
     73 
     74     thrown.expect(NullPointerException.class);
     75     thrown.expectMessage("channel");
     76 
     77     grpcCleanup.register(channel);
     78   }
     79 
     80   @Test
     81   public void registerNullServerThrowsNpe() {
     82     Server server = null;
     83     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
     84 
     85     thrown.expect(NullPointerException.class);
     86     thrown.expectMessage("server");
     87 
     88     grpcCleanup.register(server);
     89   }
     90 
     91   @Test
     92   public void singleChannelCleanup() throws Throwable {
     93     // setup
     94     ManagedChannel channel = mock(ManagedChannel.class);
     95     Statement statement = mock(Statement.class);
     96     InOrder inOrder = inOrder(statement, channel);
     97     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
     98 
     99     // run
    100     grpcCleanup.register(channel);
    101 
    102     boolean awaitTerminationFailed = false;
    103     try {
    104       // will throw because channel.awaitTermination(long, TimeUnit) will return false;
    105       grpcCleanup.apply(statement, null /* description*/).evaluate();
    106     } catch (AssertionError e) {
    107       awaitTerminationFailed = true;
    108     }
    109 
    110     // verify
    111     assertTrue(awaitTerminationFailed);
    112     inOrder.verify(statement).evaluate();
    113     inOrder.verify(channel).shutdown();
    114     inOrder.verify(channel).awaitTermination(anyLong(), any(TimeUnit.class));
    115     inOrder.verify(channel).shutdownNow();
    116   }
    117 
    118   @Test
    119   public void singleServerCleanup() throws Throwable {
    120     // setup
    121     Server server = mock(Server.class);
    122     Statement statement = mock(Statement.class);
    123     InOrder inOrder = inOrder(statement, server);
    124     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
    125 
    126     // run
    127     grpcCleanup.register(server);
    128 
    129     boolean awaitTerminationFailed = false;
    130     try {
    131       // will throw because channel.awaitTermination(long, TimeUnit) will return false;
    132       grpcCleanup.apply(statement, null /* description*/).evaluate();
    133     } catch (AssertionError e) {
    134       awaitTerminationFailed = true;
    135     }
    136 
    137     // verify
    138     assertTrue(awaitTerminationFailed);
    139     inOrder.verify(statement).evaluate();
    140     inOrder.verify(server).shutdown();
    141     inOrder.verify(server).awaitTermination(anyLong(), any(TimeUnit.class));
    142     inOrder.verify(server).shutdownNow();
    143   }
    144 
    145   @Test
    146   public void multiResource_cleanupGracefully() throws Throwable {
    147     // setup
    148     Resource resource1 = mock(Resource.class);
    149     Resource resource2 = mock(Resource.class);
    150     Resource resource3 = mock(Resource.class);
    151     doReturn(true).when(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
    152     doReturn(true).when(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
    153     doReturn(true).when(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
    154 
    155     Statement statement = mock(Statement.class);
    156     InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
    157     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
    158 
    159     // run
    160     grpcCleanup.register(resource1);
    161     grpcCleanup.register(resource2);
    162     grpcCleanup.register(resource3);
    163     grpcCleanup.apply(statement, null /* description*/).evaluate();
    164 
    165     // Verify.
    166     inOrder.verify(statement).evaluate();
    167 
    168     inOrder.verify(resource3).cleanUp();
    169     inOrder.verify(resource2).cleanUp();
    170     inOrder.verify(resource1).cleanUp();
    171 
    172     inOrder.verify(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
    173     inOrder.verify(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
    174     inOrder.verify(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
    175 
    176     inOrder.verifyNoMoreInteractions();
    177 
    178     verify(resource1, never()).forceCleanUp();
    179     verify(resource2, never()).forceCleanUp();
    180     verify(resource3, never()).forceCleanUp();
    181   }
    182 
    183   @Test
    184   public void baseTestFails() throws Throwable {
    185     // setup
    186     Resource resource = mock(Resource.class);
    187 
    188     Statement statement = mock(Statement.class);
    189     doThrow(new Exception()).when(statement).evaluate();
    190 
    191     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
    192 
    193     // run
    194     grpcCleanup.register(resource);
    195 
    196     boolean baseTestFailed = false;
    197     try {
    198       grpcCleanup.apply(statement, null /* description*/).evaluate();
    199     } catch (Exception e) {
    200       baseTestFailed = true;
    201     }
    202 
    203     // verify
    204     assertTrue(baseTestFailed);
    205 
    206     verify(resource).forceCleanUp();
    207     verifyNoMoreInteractions(resource);
    208 
    209     verify(resource, never()).cleanUp();
    210     verify(resource, never()).awaitReleased(anyLong(), any(TimeUnit.class));
    211   }
    212 
    213   @Test
    214   public void multiResource_awaitReleasedFails() throws Throwable {
    215     // setup
    216     Resource resource1 = mock(Resource.class);
    217     Resource resource2 = mock(Resource.class);
    218     Resource resource3 = mock(Resource.class);
    219     doReturn(true).when(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
    220     doReturn(false).when(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
    221     doReturn(true).when(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
    222 
    223     Statement statement = mock(Statement.class);
    224     InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
    225     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
    226 
    227     // run
    228     grpcCleanup.register(resource1);
    229     grpcCleanup.register(resource2);
    230     grpcCleanup.register(resource3);
    231 
    232     boolean cleanupFailed = false;
    233     try {
    234       grpcCleanup.apply(statement, null /* description*/).evaluate();
    235     } catch (AssertionError e) {
    236       cleanupFailed = true;
    237     }
    238 
    239     // verify
    240     assertTrue(cleanupFailed);
    241 
    242     inOrder.verify(statement).evaluate();
    243 
    244     inOrder.verify(resource3).cleanUp();
    245     inOrder.verify(resource2).cleanUp();
    246     inOrder.verify(resource1).cleanUp();
    247 
    248     inOrder.verify(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
    249     inOrder.verify(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
    250     inOrder.verify(resource2).forceCleanUp();
    251     inOrder.verify(resource1).forceCleanUp();
    252 
    253     inOrder.verifyNoMoreInteractions();
    254 
    255     verify(resource3, never()).forceCleanUp();
    256     verify(resource1, never()).awaitReleased(anyLong(), any(TimeUnit.class));
    257   }
    258 
    259   @Test
    260   public void multiResource_awaitReleasedInterrupted() throws Throwable {
    261     // setup
    262     Resource resource1 = mock(Resource.class);
    263     Resource resource2 = mock(Resource.class);
    264     Resource resource3 = mock(Resource.class);
    265     doReturn(true).when(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
    266     doThrow(new InterruptedException())
    267         .when(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
    268     doReturn(true).when(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
    269 
    270     Statement statement = mock(Statement.class);
    271     InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
    272     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
    273 
    274     // run
    275     grpcCleanup.register(resource1);
    276     grpcCleanup.register(resource2);
    277     grpcCleanup.register(resource3);
    278 
    279     boolean cleanupFailed = false;
    280     try {
    281       grpcCleanup.apply(statement, null /* description*/).evaluate();
    282     } catch (InterruptedException e) {
    283       cleanupFailed = true;
    284     }
    285 
    286     // verify
    287     assertTrue(cleanupFailed);
    288     assertTrue(Thread.interrupted());
    289 
    290     inOrder.verify(statement).evaluate();
    291 
    292     inOrder.verify(resource3).cleanUp();
    293     inOrder.verify(resource2).cleanUp();
    294     inOrder.verify(resource1).cleanUp();
    295 
    296     inOrder.verify(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
    297     inOrder.verify(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
    298     inOrder.verify(resource2).forceCleanUp();
    299     inOrder.verify(resource1).forceCleanUp();
    300 
    301     inOrder.verifyNoMoreInteractions();
    302 
    303     verify(resource3, never()).forceCleanUp();
    304     verify(resource1, never()).awaitReleased(anyLong(), any(TimeUnit.class));
    305   }
    306 
    307   @Test
    308   public void multiResource_timeoutCalculation() throws Throwable {
    309     // setup
    310 
    311     Resource resource1 = mock(FakeResource.class,
    312         delegatesTo(new FakeResource(1 /* cleanupNanos */, 10 /* awaitReleaseNanos */)));
    313 
    314     Resource resource2 = mock(FakeResource.class,
    315         delegatesTo(new FakeResource(100 /* cleanupNanos */, 1000 /* awaitReleaseNanos */)));
    316 
    317 
    318     Statement statement = mock(Statement.class);
    319     InOrder inOrder = inOrder(statement, resource1, resource2);
    320     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule().setTicker(fakeClock.getTicker());
    321 
    322     // run
    323     grpcCleanup.register(resource1);
    324     grpcCleanup.register(resource2);
    325     grpcCleanup.apply(statement, null /* description*/).evaluate();
    326 
    327     // verify
    328     inOrder.verify(statement).evaluate();
    329 
    330     inOrder.verify(resource2).cleanUp();
    331     inOrder.verify(resource1).cleanUp();
    332 
    333     inOrder.verify(resource2).awaitReleased(
    334         TimeUnit.SECONDS.toNanos(10) - 100 - 1, TimeUnit.NANOSECONDS);
    335     inOrder.verify(resource1).awaitReleased(
    336         TimeUnit.SECONDS.toNanos(10) - 100 - 1 - 1000, TimeUnit.NANOSECONDS);
    337 
    338     inOrder.verifyNoMoreInteractions();
    339 
    340     verify(resource2, never()).forceCleanUp();
    341     verify(resource1, never()).forceCleanUp();
    342   }
    343 
    344   @Test
    345   public void multiResource_timeoutCalculation_customTimeout() throws Throwable {
    346     // setup
    347 
    348     Resource resource1 = mock(FakeResource.class,
    349         delegatesTo(new FakeResource(1 /* cleanupNanos */, 10 /* awaitReleaseNanos */)));
    350 
    351     Resource resource2 = mock(FakeResource.class,
    352         delegatesTo(new FakeResource(100 /* cleanupNanos */, 1000 /* awaitReleaseNanos */)));
    353 
    354 
    355     Statement statement = mock(Statement.class);
    356     InOrder inOrder = inOrder(statement, resource1, resource2);
    357     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule()
    358         .setTicker(fakeClock.getTicker()).setTimeout(3000, TimeUnit.NANOSECONDS);
    359 
    360     // run
    361     grpcCleanup.register(resource1);
    362     grpcCleanup.register(resource2);
    363     grpcCleanup.apply(statement, null /* description*/).evaluate();
    364 
    365     // verify
    366     inOrder.verify(statement).evaluate();
    367 
    368     inOrder.verify(resource2).cleanUp();
    369     inOrder.verify(resource1).cleanUp();
    370 
    371     inOrder.verify(resource2).awaitReleased(3000 - 100 - 1, TimeUnit.NANOSECONDS);
    372     inOrder.verify(resource1).awaitReleased(3000 - 100 - 1 - 1000, TimeUnit.NANOSECONDS);
    373 
    374     inOrder.verifyNoMoreInteractions();
    375 
    376     verify(resource2, never()).forceCleanUp();
    377     verify(resource1, never()).forceCleanUp();
    378   }
    379 
    380   @Test
    381   public void baseTestFailsThenCleanupFails() throws Throwable {
    382     // setup
    383     Exception baseTestFailure = new Exception();
    384 
    385     Statement statement = mock(Statement.class);
    386     doThrow(baseTestFailure).when(statement).evaluate();
    387 
    388     Resource resource1 = mock(Resource.class);
    389     Resource resource2 = mock(Resource.class);
    390     Resource resource3 = mock(Resource.class);
    391     doThrow(new RuntimeException()).when(resource2).forceCleanUp();
    392 
    393     InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
    394     GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
    395 
    396     // run
    397     grpcCleanup.register(resource1);
    398     grpcCleanup.register(resource2);
    399     grpcCleanup.register(resource3);
    400 
    401     Throwable failure = null;
    402     try {
    403       grpcCleanup.apply(statement, null /* description*/).evaluate();
    404     } catch (Throwable e) {
    405       failure = e;
    406     }
    407 
    408     // verify
    409     assertThat(failure).isInstanceOf(MultipleFailureException.class);
    410     assertSame(baseTestFailure, ((MultipleFailureException) failure).getFailures().get(0));
    411 
    412     inOrder.verify(statement).evaluate();
    413     inOrder.verify(resource3).forceCleanUp();
    414     inOrder.verify(resource2).forceCleanUp();
    415     inOrder.verifyNoMoreInteractions();
    416 
    417     verify(resource1, never()).cleanUp();
    418     verify(resource2, never()).cleanUp();
    419     verify(resource3, never()).cleanUp();
    420     verify(resource1, never()).forceCleanUp();
    421   }
    422 
    423   public static class FakeResource implements Resource {
    424     private final long cleanupNanos;
    425     private final long awaitReleaseNanos;
    426 
    427     private FakeResource(long cleanupNanos, long awaitReleaseNanos) {
    428       this.cleanupNanos = cleanupNanos;
    429       this.awaitReleaseNanos = awaitReleaseNanos;
    430     }
    431 
    432     @Override
    433     public void cleanUp() {
    434       fakeClock.forwardTime(cleanupNanos, TimeUnit.NANOSECONDS);
    435     }
    436 
    437     @Override
    438     public void forceCleanUp() {
    439     }
    440 
    441     @Override
    442     public boolean awaitReleased(long duration, TimeUnit timeUnit) {
    443       fakeClock.forwardTime(awaitReleaseNanos, TimeUnit.NANOSECONDS);
    444       return true;
    445     }
    446   }
    447 }
    448