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@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 setUp()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(). */ testCallMethod()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(). */ testGetPrototype()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. */ testStub()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. */ testBlockingStub()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 testNewReflectiveService()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 testNewReflectiveBlockingService()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 testNoGenericServices()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 */ wrapsCallback( MockCallback<?> callback)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 isCalled()292 public boolean isCalled() { return called; } 293 reset()294 public void reset() { called = false; } 295 @Override run(Type message)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 WrapsCallback(MockCallback<?> callback)304 public WrapsCallback(MockCallback<?> callback) { 305 this.callback = callback; 306 } 307 308 @Override 309 @SuppressWarnings("unchecked") matches(Object actual)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 appendTo(StringBuffer buffer)322 public void appendTo(StringBuffer buffer) { 323 buffer.append("wrapsCallback(mockCallback)"); 324 } 325 } 326 } 327