Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      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.TestAllTypes;
     39 import protobuf_unittest.UnittestProto.TestService;
     40 import protobuf_unittest.UnittestProto.FooRequest;
     41 import protobuf_unittest.UnittestProto.FooResponse;
     42 import protobuf_unittest.UnittestProto.BarRequest;
     43 import protobuf_unittest.UnittestProto.BarResponse;
     44 
     45 import org.easymock.classextension.EasyMock;
     46 import org.easymock.classextension.IMocksControl;
     47 import org.easymock.IArgumentMatcher;
     48 
     49 import java.util.HashSet;
     50 import java.util.Set;
     51 
     52 import junit.framework.TestCase;
     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 = new RpcCallback<Message>() {
    179       public void run(Message parameter) {
    180         // No reason this should be run.
    181         fail();
    182       }
    183     };
    184     RpcCallback<TestAllTypes> specializedCallback =
    185         RpcUtil.specializeCallback(callback);
    186 
    187     impl.foo(EasyMock.same(controller), EasyMock.same(request),
    188         EasyMock.same(specializedCallback));
    189     EasyMock.expectLastCall();
    190 
    191     control.replay();
    192 
    193     service.callMethod(fooMethod, controller, request, callback);
    194 
    195     control.verify();
    196   }
    197 
    198   public void testNewReflectiveBlockingService() throws ServiceException {
    199     ServiceWithNoOuter.BlockingInterface impl =
    200         control.createMock(ServiceWithNoOuter.BlockingInterface.class);
    201     RpcController controller = control.createMock(RpcController.class);
    202     BlockingService service =
    203         ServiceWithNoOuter.newReflectiveBlockingService(impl);
    204 
    205     MethodDescriptor fooMethod =
    206         ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
    207     MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
    208     RpcCallback<Message> callback = new RpcCallback<Message>() {
    209       public void run(Message parameter) {
    210         // No reason this should be run.
    211         fail();
    212       }
    213     };
    214 
    215     TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
    216     EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
    217         .andReturn(expectedResponse);
    218 
    219     control.replay();
    220 
    221     Message response =
    222         service.callBlockingMethod(fooMethod, controller, request);
    223     assertEquals(expectedResponse, response);
    224 
    225     control.verify();
    226   }
    227 
    228   public void testNoGenericServices() throws Exception {
    229     // Non-services should be usable.
    230     UnittestNoGenericServices.TestMessage message =
    231       UnittestNoGenericServices.TestMessage.newBuilder()
    232         .setA(123)
    233         .setExtension(UnittestNoGenericServices.testExtension, 456)
    234         .build();
    235     assertEquals(123, message.getA());
    236     assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
    237 
    238     // Build a list of the class names nested in UnittestNoGenericServices.
    239     String outerName = "google.protobuf.no_generic_services_test." +
    240                        "UnittestNoGenericServices";
    241     Class<?> outerClass = Class.forName(outerName);
    242 
    243     Set<String> innerClassNames = new HashSet<String>();
    244     for (Class<?> innerClass : outerClass.getClasses()) {
    245       String fullName = innerClass.getName();
    246       // Figure out the unqualified name of the inner class.
    247       // Note:  Surprisingly, the full name of an inner class will be separated
    248       //   from the outer class name by a '$' rather than a '.'.  This is not
    249       //   mentioned in the documentation for java.lang.Class.  I don't want to
    250       //   make assumptions, so I'm just going to accept any character as the
    251       //   separator.
    252       assertTrue(fullName.startsWith(outerName));
    253       innerClassNames.add(fullName.substring(outerName.length() + 1));
    254     }
    255 
    256     // No service class should have been generated.
    257     assertTrue(innerClassNames.contains("TestMessage"));
    258     assertTrue(innerClassNames.contains("TestEnum"));
    259     assertFalse(innerClassNames.contains("TestService"));
    260 
    261     // But descriptors are there.
    262     FileDescriptor file = UnittestNoGenericServices.getDescriptor();
    263     assertEquals(1, file.getServices().size());
    264     assertEquals("TestService", file.getServices().get(0).getName());
    265     assertEquals(1, file.getServices().get(0).getMethods().size());
    266     assertEquals("Foo",
    267         file.getServices().get(0).getMethods().get(0).getName());
    268   }
    269 
    270   // =================================================================
    271 
    272   /**
    273    * wrapsCallback() is an EasyMock argument predicate.  wrapsCallback(c)
    274    * matches a callback if calling that callback causes c to be called.
    275    * In other words, c wraps the given callback.
    276    */
    277   private <Type extends Message> RpcCallback<Type> wrapsCallback(
    278       MockCallback<?> callback) {
    279     EasyMock.reportMatcher(new WrapsCallback(callback));
    280     return null;
    281   }
    282 
    283   /** The parameter to wrapsCallback() must be a MockCallback. */
    284   private static class MockCallback<Type extends Message>
    285       implements RpcCallback<Type> {
    286     private boolean called = false;
    287 
    288     public boolean isCalled() { return called; }
    289 
    290     public void reset() { called = false; }
    291     public void run(Type message) { called = true; }
    292   }
    293 
    294   /** Implementation of the wrapsCallback() argument matcher. */
    295   private static class WrapsCallback implements IArgumentMatcher {
    296     private MockCallback<?> callback;
    297 
    298     public WrapsCallback(MockCallback<?> callback) {
    299       this.callback = callback;
    300     }
    301 
    302     @SuppressWarnings("unchecked")
    303     public boolean matches(Object actual) {
    304       if (!(actual instanceof RpcCallback)) {
    305         return false;
    306       }
    307       RpcCallback actualCallback = (RpcCallback)actual;
    308 
    309       callback.reset();
    310       actualCallback.run(null);
    311       return callback.isCalled();
    312     }
    313 
    314     public void appendTo(StringBuffer buffer) {
    315       buffer.append("wrapsCallback(mockCallback)");
    316     }
    317   }
    318 }
    319