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 31package com.google.protobuf; 32 33import com.google.protobuf.Descriptors.FileDescriptor; 34import com.google.protobuf.Descriptors.MethodDescriptor; 35import google.protobuf.no_generic_services_test.UnittestNoGenericServices; 36import protobuf_unittest.MessageWithNoOuter; 37import protobuf_unittest.ServiceWithNoOuter; 38import protobuf_unittest.UnittestProto.TestAllTypes; 39import protobuf_unittest.UnittestProto.TestService; 40import protobuf_unittest.UnittestProto.FooRequest; 41import protobuf_unittest.UnittestProto.FooResponse; 42import protobuf_unittest.UnittestProto.BarRequest; 43import protobuf_unittest.UnittestProto.BarResponse; 44 45import org.easymock.classextension.EasyMock; 46import org.easymock.classextension.IMocksControl; 47import org.easymock.IArgumentMatcher; 48 49import java.util.HashSet; 50import java.util.Set; 51 52import junit.framework.TestCase; 53 54/** 55 * Tests services and stubs. 56 * 57 * @author kenton@google.com Kenton Varda 58 */ 59public 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