Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 package com.google.protobuf;
     32 
     33 import com.google.protobuf.Descriptors.FileDescriptor;
     34 import com.google.protobuf.Descriptors.MethodDescriptor;
     35 import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
     36 import protobuf_unittest.MessageWithNoOuter;
     37 import protobuf_unittest.ServiceWithNoOuter;
     38 import protobuf_unittest.UnittestProto.BarRequest;
     39 import protobuf_unittest.UnittestProto.BarResponse;
     40 import protobuf_unittest.UnittestProto.FooRequest;
     41 import protobuf_unittest.UnittestProto.FooResponse;
     42 import protobuf_unittest.UnittestProto.TestAllTypes;
     43 import protobuf_unittest.UnittestProto.TestService;
     44 
     45 import junit.framework.TestCase;
     46 
     47 import org.easymock.classextension.EasyMock;
     48 import org.easymock.IArgumentMatcher;
     49 import org.easymock.classextension.IMocksControl;
     50 
     51 import java.util.HashSet;
     52 import java.util.Set;
     53 
     54 /**
     55  * Tests services and stubs.
     56  *
     57  * @author kenton (at) google.com Kenton Varda
     58  */
     59 public class ServiceTest extends TestCase {
     60   private IMocksControl control;
     61   private RpcController mockController;
     62 
     63   private final Descriptors.MethodDescriptor fooDescriptor =
     64     TestService.getDescriptor().getMethods().get(0);
     65   private final Descriptors.MethodDescriptor barDescriptor =
     66     TestService.getDescriptor().getMethods().get(1);
     67 
     68   @Override
     69   protected void setUp() throws Exception {
     70     super.setUp();
     71     control = EasyMock.createStrictControl();
     72     mockController = control.createMock(RpcController.class);
     73   }
     74 
     75   // =================================================================
     76 
     77   /** Tests Service.callMethod(). */
     78   public void testCallMethod() throws Exception {
     79     FooRequest fooRequest = FooRequest.newBuilder().build();
     80     BarRequest barRequest = BarRequest.newBuilder().build();
     81     MockCallback<Message> fooCallback = new MockCallback<Message>();
     82     MockCallback<Message> barCallback = new MockCallback<Message>();
     83     TestService mockService = control.createMock(TestService.class);
     84 
     85     mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
     86                     this.<FooResponse>wrapsCallback(fooCallback));
     87     mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
     88                     this.<BarResponse>wrapsCallback(barCallback));
     89     control.replay();
     90 
     91     mockService.callMethod(fooDescriptor, mockController,
     92                            fooRequest, fooCallback);
     93     mockService.callMethod(barDescriptor, mockController,
     94                            barRequest, barCallback);
     95     control.verify();
     96   }
     97 
     98   /** Tests Service.get{Request,Response}Prototype(). */
     99   public void testGetPrototype() throws Exception {
    100     TestService mockService = control.createMock(TestService.class);
    101 
    102     assertSame(mockService.getRequestPrototype(fooDescriptor),
    103                FooRequest.getDefaultInstance());
    104     assertSame(mockService.getResponsePrototype(fooDescriptor),
    105                FooResponse.getDefaultInstance());
    106     assertSame(mockService.getRequestPrototype(barDescriptor),
    107                BarRequest.getDefaultInstance());
    108     assertSame(mockService.getResponsePrototype(barDescriptor),
    109                BarResponse.getDefaultInstance());
    110   }
    111 
    112   /** Tests generated stubs. */
    113   public void testStub() throws Exception {
    114     FooRequest fooRequest = FooRequest.newBuilder().build();
    115     BarRequest barRequest = BarRequest.newBuilder().build();
    116     MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
    117     MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
    118     RpcChannel mockChannel = control.createMock(RpcChannel.class);
    119     TestService stub = TestService.newStub(mockChannel);
    120 
    121     mockChannel.callMethod(
    122       EasyMock.same(fooDescriptor),
    123       EasyMock.same(mockController),
    124       EasyMock.same(fooRequest),
    125       EasyMock.same(FooResponse.getDefaultInstance()),
    126       this.<Message>wrapsCallback(fooCallback));
    127     mockChannel.callMethod(
    128       EasyMock.same(barDescriptor),
    129       EasyMock.same(mockController),
    130       EasyMock.same(barRequest),
    131       EasyMock.same(BarResponse.getDefaultInstance()),
    132       this.<Message>wrapsCallback(barCallback));
    133     control.replay();
    134 
    135     stub.foo(mockController, fooRequest, fooCallback);
    136     stub.bar(mockController, barRequest, barCallback);
    137     control.verify();
    138   }
    139 
    140   /** Tests generated blocking stubs. */
    141   public void testBlockingStub() throws Exception {
    142     FooRequest fooRequest = FooRequest.newBuilder().build();
    143     BarRequest barRequest = BarRequest.newBuilder().build();
    144     BlockingRpcChannel mockChannel =
    145         control.createMock(BlockingRpcChannel.class);
    146     TestService.BlockingInterface stub =
    147         TestService.newBlockingStub(mockChannel);
    148 
    149     FooResponse fooResponse = FooResponse.newBuilder().build();
    150     BarResponse barResponse = BarResponse.newBuilder().build();
    151 
    152     EasyMock.expect(mockChannel.callBlockingMethod(
    153       EasyMock.same(fooDescriptor),
    154       EasyMock.same(mockController),
    155       EasyMock.same(fooRequest),
    156       EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
    157     EasyMock.expect(mockChannel.callBlockingMethod(
    158       EasyMock.same(barDescriptor),
    159       EasyMock.same(mockController),
    160       EasyMock.same(barRequest),
    161       EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
    162     control.replay();
    163 
    164     assertSame(fooResponse, stub.foo(mockController, fooRequest));
    165     assertSame(barResponse, stub.bar(mockController, barRequest));
    166     control.verify();
    167   }
    168 
    169   public void testNewReflectiveService() {
    170     ServiceWithNoOuter.Interface impl =
    171         control.createMock(ServiceWithNoOuter.Interface.class);
    172     RpcController controller = control.createMock(RpcController.class);
    173     Service service = ServiceWithNoOuter.newReflectiveService(impl);
    174 
    175     MethodDescriptor fooMethod =
    176         ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
    177     MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
    178     RpcCallback<Message> callback =
    179         new RpcCallback<Message>() {
    180           @Override
    181           public void run(Message parameter) {
    182             // No reason this should be run.
    183             fail();
    184           }
    185         };
    186     RpcCallback<TestAllTypes> specializedCallback =
    187         RpcUtil.specializeCallback(callback);
    188 
    189     impl.foo(EasyMock.same(controller), EasyMock.same(request),
    190         EasyMock.same(specializedCallback));
    191     EasyMock.expectLastCall();
    192 
    193     control.replay();
    194 
    195     service.callMethod(fooMethod, controller, request, callback);
    196 
    197     control.verify();
    198   }
    199 
    200   public void testNewReflectiveBlockingService() throws ServiceException {
    201     ServiceWithNoOuter.BlockingInterface impl =
    202         control.createMock(ServiceWithNoOuter.BlockingInterface.class);
    203     RpcController controller = control.createMock(RpcController.class);
    204     BlockingService service =
    205         ServiceWithNoOuter.newReflectiveBlockingService(impl);
    206 
    207     MethodDescriptor fooMethod =
    208         ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
    209     MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
    210 
    211     TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
    212     EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
    213         .andReturn(expectedResponse);
    214 
    215     control.replay();
    216 
    217     Message response =
    218         service.callBlockingMethod(fooMethod, controller, request);
    219     assertEquals(expectedResponse, response);
    220 
    221     control.verify();
    222   }
    223 
    224   public void testNoGenericServices() throws Exception {
    225     // Non-services should be usable.
    226     UnittestNoGenericServices.TestMessage message =
    227       UnittestNoGenericServices.TestMessage.newBuilder()
    228         .setA(123)
    229         .setExtension(UnittestNoGenericServices.testExtension, 456)
    230         .build();
    231     assertEquals(123, message.getA());
    232     assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
    233 
    234     // Build a list of the class names nested in UnittestNoGenericServices.
    235     String outerName = "google.protobuf.no_generic_services_test." +
    236                        "UnittestNoGenericServices";
    237     Class<?> outerClass = Class.forName(outerName);
    238 
    239     Set<String> innerClassNames = new HashSet<String>();
    240     for (Class<?> innerClass : outerClass.getClasses()) {
    241       String fullName = innerClass.getName();
    242       // Figure out the unqualified name of the inner class.
    243       // Note:  Surprisingly, the full name of an inner class will be separated
    244       //   from the outer class name by a '$' rather than a '.'.  This is not
    245       //   mentioned in the documentation for java.lang.Class.  I don't want to
    246       //   make assumptions, so I'm just going to accept any character as the
    247       //   separator.
    248       assertTrue(fullName.startsWith(outerName));
    249 
    250       if (!Service.class.isAssignableFrom(innerClass) &&
    251           !Message.class.isAssignableFrom(innerClass) &&
    252           !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
    253         // Ignore any classes not generated by the base code generator.
    254         continue;
    255       }
    256 
    257       innerClassNames.add(fullName.substring(outerName.length() + 1));
    258     }
    259 
    260     // No service class should have been generated.
    261     assertTrue(innerClassNames.contains("TestMessage"));
    262     assertTrue(innerClassNames.contains("TestEnum"));
    263     assertFalse(innerClassNames.contains("TestService"));
    264 
    265     // But descriptors are there.
    266     FileDescriptor file = UnittestNoGenericServices.getDescriptor();
    267     assertEquals(1, file.getServices().size());
    268     assertEquals("TestService", file.getServices().get(0).getName());
    269     assertEquals(1, file.getServices().get(0).getMethods().size());
    270     assertEquals("Foo",
    271         file.getServices().get(0).getMethods().get(0).getName());
    272   }
    273 
    274   // =================================================================
    275 
    276   /**
    277    * wrapsCallback() is an EasyMock argument predicate.  wrapsCallback(c)
    278    * matches a callback if calling that callback causes c to be called.
    279    * In other words, c wraps the given callback.
    280    */
    281   private <Type extends Message> RpcCallback<Type> wrapsCallback(
    282       MockCallback<?> callback) {
    283     EasyMock.reportMatcher(new WrapsCallback(callback));
    284     return null;
    285   }
    286 
    287   /** The parameter to wrapsCallback() must be a MockCallback. */
    288   private static class MockCallback<Type extends Message>
    289       implements RpcCallback<Type> {
    290     private boolean called = false;
    291 
    292     public boolean isCalled() { return called; }
    293 
    294     public void reset() { called = false; }
    295     @Override
    296     public void run(Type message) {
    297       called = true; }
    298   }
    299 
    300   /** Implementation of the wrapsCallback() argument matcher. */
    301   private static class WrapsCallback implements IArgumentMatcher {
    302     private MockCallback<?> callback;
    303 
    304     public WrapsCallback(MockCallback<?> callback) {
    305       this.callback = callback;
    306     }
    307 
    308     @Override
    309     @SuppressWarnings("unchecked")
    310     public boolean matches(Object actual) {
    311       if (!(actual instanceof RpcCallback)) {
    312         return false;
    313       }
    314       RpcCallback actualCallback = (RpcCallback)actual;
    315 
    316       callback.reset();
    317       actualCallback.run(null);
    318       return callback.isCalled();
    319     }
    320 
    321     @Override
    322     public void appendTo(StringBuffer buffer) {
    323       buffer.append("wrapsCallback(mockCallback)");
    324     }
    325   }
    326 }
    327