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 protobuf_unittest.MessageWithNoOuter; 36 import protobuf_unittest.ServiceWithNoOuter; 37 import protobuf_unittest.UnittestProto.BarRequest; 38 import protobuf_unittest.UnittestProto.BarResponse; 39 import protobuf_unittest.UnittestProto.FooRequest; 40 import protobuf_unittest.UnittestProto.FooResponse; 41 import protobuf_unittest.UnittestProto.TestAllTypes; 42 import protobuf_unittest.UnittestProto.TestService; 43 import protobuf_unittest.no_generic_services_test.UnittestNoGenericServices; 44 import java.util.HashSet; 45 import java.util.Set; 46 import junit.framework.TestCase; 47 import org.easymock.classextension.EasyMock; 48 import org.easymock.IArgumentMatcher; 49 import org.easymock.classextension.IMocksControl; 50 51 /** 52 * Tests services and stubs. 53 * 54 * @author kenton@google.com Kenton Varda 55 */ 56 public class ServiceTest extends TestCase { 57 private IMocksControl control; 58 private RpcController mockController; 59 60 private final Descriptors.MethodDescriptor fooDescriptor = 61 TestService.getDescriptor().getMethods().get(0); 62 private final Descriptors.MethodDescriptor barDescriptor = 63 TestService.getDescriptor().getMethods().get(1); 64 65 @Override setUp()66 protected void setUp() throws Exception { 67 super.setUp(); 68 control = EasyMock.createStrictControl(); 69 mockController = control.createMock(RpcController.class); 70 } 71 72 // ================================================================= 73 74 /** Tests Service.callMethod(). */ testCallMethod()75 public void testCallMethod() throws Exception { 76 FooRequest fooRequest = FooRequest.newBuilder().build(); 77 BarRequest barRequest = BarRequest.newBuilder().build(); 78 MockCallback<Message> fooCallback = new MockCallback<Message>(); 79 MockCallback<Message> barCallback = new MockCallback<Message>(); 80 TestService mockService = control.createMock(TestService.class); 81 82 mockService.foo( 83 EasyMock.same(mockController), 84 EasyMock.same(fooRequest), 85 this.<FooResponse>wrapsCallback(fooCallback)); 86 mockService.bar( 87 EasyMock.same(mockController), 88 EasyMock.same(barRequest), 89 this.<BarResponse>wrapsCallback(barCallback)); 90 control.replay(); 91 92 mockService.callMethod( 93 fooDescriptor, mockController, 94 fooRequest, fooCallback); 95 mockService.callMethod( 96 barDescriptor, mockController, 97 barRequest, barCallback); 98 control.verify(); 99 } 100 101 /** Tests Service.get{Request,Response}Prototype(). */ testGetPrototype()102 public void testGetPrototype() throws Exception { 103 TestService mockService = control.createMock(TestService.class); 104 105 assertSame(mockService.getRequestPrototype(fooDescriptor), FooRequest.getDefaultInstance()); 106 assertSame(mockService.getResponsePrototype(fooDescriptor), FooResponse.getDefaultInstance()); 107 assertSame(mockService.getRequestPrototype(barDescriptor), BarRequest.getDefaultInstance()); 108 assertSame(mockService.getResponsePrototype(barDescriptor), BarResponse.getDefaultInstance()); 109 } 110 111 /** Tests generated stubs. */ testStub()112 public void testStub() throws Exception { 113 FooRequest fooRequest = FooRequest.newBuilder().build(); 114 BarRequest barRequest = BarRequest.newBuilder().build(); 115 MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>(); 116 MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>(); 117 RpcChannel mockChannel = control.createMock(RpcChannel.class); 118 TestService stub = TestService.newStub(mockChannel); 119 120 mockChannel.callMethod( 121 EasyMock.same(fooDescriptor), 122 EasyMock.same(mockController), 123 EasyMock.same(fooRequest), 124 EasyMock.same(FooResponse.getDefaultInstance()), 125 this.<Message>wrapsCallback(fooCallback)); 126 mockChannel.callMethod( 127 EasyMock.same(barDescriptor), 128 EasyMock.same(mockController), 129 EasyMock.same(barRequest), 130 EasyMock.same(BarResponse.getDefaultInstance()), 131 this.<Message>wrapsCallback(barCallback)); 132 control.replay(); 133 134 stub.foo(mockController, fooRequest, fooCallback); 135 stub.bar(mockController, barRequest, barCallback); 136 control.verify(); 137 } 138 139 /** Tests generated blocking stubs. */ testBlockingStub()140 public void testBlockingStub() throws Exception { 141 FooRequest fooRequest = FooRequest.newBuilder().build(); 142 BarRequest barRequest = BarRequest.newBuilder().build(); 143 BlockingRpcChannel mockChannel = control.createMock(BlockingRpcChannel.class); 144 TestService.BlockingInterface stub = TestService.newBlockingStub(mockChannel); 145 146 FooResponse fooResponse = FooResponse.newBuilder().build(); 147 BarResponse barResponse = BarResponse.newBuilder().build(); 148 149 EasyMock.expect( 150 mockChannel.callBlockingMethod( 151 EasyMock.same(fooDescriptor), 152 EasyMock.same(mockController), 153 EasyMock.same(fooRequest), 154 EasyMock.same(FooResponse.getDefaultInstance()))) 155 .andReturn(fooResponse); 156 EasyMock.expect( 157 mockChannel.callBlockingMethod( 158 EasyMock.same(barDescriptor), 159 EasyMock.same(mockController), 160 EasyMock.same(barRequest), 161 EasyMock.same(BarResponse.getDefaultInstance()))) 162 .andReturn(barResponse); 163 control.replay(); 164 165 assertSame(fooResponse, stub.foo(mockController, fooRequest)); 166 assertSame(barResponse, stub.bar(mockController, barRequest)); 167 control.verify(); 168 } 169 testNewReflectiveService()170 public void testNewReflectiveService() { 171 ServiceWithNoOuter.Interface impl = control.createMock(ServiceWithNoOuter.Interface.class); 172 RpcController controller = control.createMock(RpcController.class); 173 Service service = ServiceWithNoOuter.newReflectiveService(impl); 174 175 MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo"); 176 MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); 177 RpcCallback<Message> callback = 178 new RpcCallback<Message>() { 179 @Override 180 public void run(Message parameter) { 181 // No reason this should be run. 182 fail(); 183 } 184 }; 185 RpcCallback<TestAllTypes> specializedCallback = RpcUtil.specializeCallback(callback); 186 187 impl.foo(EasyMock.same(controller), EasyMock.same(request), EasyMock.same(specializedCallback)); 188 EasyMock.expectLastCall(); 189 190 control.replay(); 191 192 service.callMethod(fooMethod, controller, request, callback); 193 194 control.verify(); 195 } 196 testNewReflectiveBlockingService()197 public void testNewReflectiveBlockingService() throws ServiceException { 198 ServiceWithNoOuter.BlockingInterface impl = 199 control.createMock(ServiceWithNoOuter.BlockingInterface.class); 200 RpcController controller = control.createMock(RpcController.class); 201 BlockingService service = ServiceWithNoOuter.newReflectiveBlockingService(impl); 202 203 MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo"); 204 MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); 205 206 TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance(); 207 EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request))) 208 .andReturn(expectedResponse); 209 210 control.replay(); 211 212 Message response = service.callBlockingMethod(fooMethod, controller, request); 213 assertEquals(expectedResponse, response); 214 215 control.verify(); 216 } 217 testNoGenericServices()218 public void testNoGenericServices() throws Exception { 219 // Non-services should be usable. 220 UnittestNoGenericServices.TestMessage message = 221 UnittestNoGenericServices.TestMessage.newBuilder() 222 .setA(123) 223 .setExtension(UnittestNoGenericServices.testExtension, 456) 224 .build(); 225 assertEquals(123, message.getA()); 226 assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber()); 227 228 // Build a list of the class names nested in UnittestNoGenericServices. 229 String outerName = 230 "protobuf_unittest.no_generic_services_test.UnittestNoGenericServices"; 231 Class<?> outerClass = Class.forName(outerName); 232 233 Set<String> innerClassNames = new HashSet<String>(); 234 for (Class<?> innerClass : outerClass.getClasses()) { 235 String fullName = innerClass.getName(); 236 // Figure out the unqualified name of the inner class. 237 // Note: Surprisingly, the full name of an inner class will be separated 238 // from the outer class name by a '$' rather than a '.'. This is not 239 // mentioned in the documentation for java.lang.Class. I don't want to 240 // make assumptions, so I'm just going to accept any character as the 241 // separator. 242 assertTrue(fullName.startsWith(outerName)); 243 244 if (!Service.class.isAssignableFrom(innerClass) 245 && !Message.class.isAssignableFrom(innerClass) 246 && !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) { 247 // Ignore any classes not generated by the base code generator. 248 continue; 249 } 250 251 innerClassNames.add(fullName.substring(outerName.length() + 1)); 252 } 253 254 // No service class should have been generated. 255 assertTrue(innerClassNames.contains("TestMessage")); 256 assertTrue(innerClassNames.contains("TestEnum")); 257 assertFalse(innerClassNames.contains("TestService")); 258 259 // But descriptors are there. 260 FileDescriptor file = UnittestNoGenericServices.getDescriptor(); 261 assertEquals(1, file.getServices().size()); 262 assertEquals("TestService", file.getServices().get(0).getName()); 263 assertEquals(1, file.getServices().get(0).getMethods().size()); 264 assertEquals("Foo", file.getServices().get(0).getMethods().get(0).getName()); 265 } 266 267 268 // ================================================================= 269 270 /** 271 * wrapsCallback() is an EasyMock argument predicate. wrapsCallback(c) matches a callback if 272 * calling that callback causes c to be called. In other words, c wraps the given callback. 273 */ wrapsCallback(MockCallback<?> callback)274 private <T extends Message> RpcCallback<T> wrapsCallback(MockCallback<?> callback) { 275 EasyMock.reportMatcher(new WrapsCallback(callback)); 276 return null; 277 } 278 279 /** The parameter to wrapsCallback() must be a MockCallback. */ 280 private static class MockCallback<T extends Message> implements RpcCallback<T> { 281 private boolean called = false; 282 isCalled()283 public boolean isCalled() { 284 return called; 285 } 286 reset()287 public void reset() { 288 called = false; 289 } 290 291 @Override run(T message)292 public void run(T message) { 293 called = true; 294 } 295 } 296 297 /** Implementation of the wrapsCallback() argument matcher. */ 298 private static class WrapsCallback implements IArgumentMatcher { 299 private MockCallback<?> callback; 300 WrapsCallback(MockCallback<?> callback)301 public WrapsCallback(MockCallback<?> callback) { 302 this.callback = callback; 303 } 304 305 @Override 306 @SuppressWarnings("unchecked") matches(Object actual)307 public boolean matches(Object actual) { 308 if (!(actual instanceof RpcCallback)) { 309 return false; 310 } 311 RpcCallback actualCallback = (RpcCallback) actual; 312 313 callback.reset(); 314 actualCallback.run(null); 315 return callback.isCalled(); 316 } 317 318 @Override appendTo(StringBuffer buffer)319 public void appendTo(StringBuffer buffer) { 320 buffer.append("wrapsCallback(mockCallback)"); 321 } 322 } 323 } 324