1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.mojo.bindings; 6 7 import android.test.suitebuilder.annotation.SmallTest; 8 9 import org.chromium.mojo.MojoTestCase; 10 import org.chromium.mojo.bindings.BindingsTestUtils.CapturingErrorHandler; 11 import org.chromium.mojo.bindings.test.mojom.imported.ImportedInterface; 12 import org.chromium.mojo.bindings.test.mojom.sample.Factory; 13 import org.chromium.mojo.bindings.test.mojom.sample.NamedObject; 14 import org.chromium.mojo.bindings.test.mojom.sample.NamedObject.GetNameResponse; 15 import org.chromium.mojo.bindings.test.mojom.sample.Request; 16 import org.chromium.mojo.bindings.test.mojom.sample.Response; 17 import org.chromium.mojo.system.DataPipe.ConsumerHandle; 18 import org.chromium.mojo.system.MessagePipeHandle; 19 import org.chromium.mojo.system.Pair; 20 import org.chromium.mojo.system.impl.CoreImpl; 21 22 import java.io.Closeable; 23 import java.util.ArrayList; 24 import java.util.Collections; 25 import java.util.List; 26 27 /** 28 * Tests for interfaces / proxies / stubs generated for sample_factory.mojom. 29 */ 30 public class InterfacesTest extends MojoTestCase { 31 32 private static final String OBJECT_NAME = "hello world"; 33 34 private final List<Closeable> mCloseablesToClose = new ArrayList<Closeable>(); 35 36 /** 37 * Basic implementation of {@link NamedObject}. 38 */ 39 public static class MockNamedObjectImpl extends CapturingErrorHandler implements NamedObject { 40 41 private String mName = ""; 42 43 /** 44 * @see org.chromium.mojo.bindings.Interface#close() 45 */ 46 @Override close()47 public void close() { 48 } 49 50 @Override setName(String name)51 public void setName(String name) { 52 mName = name; 53 } 54 55 @Override getName(GetNameResponse callback)56 public void getName(GetNameResponse callback) { 57 callback.call(mName); 58 } 59 getNameSynchronously()60 public String getNameSynchronously() { 61 return mName; 62 } 63 } 64 65 /** 66 * Implementation of {@link GetNameResponse} keeping track of usage. 67 */ 68 public static class RecordingGetNameResponse implements GetNameResponse { 69 private String mName; 70 private boolean mCalled; 71 RecordingGetNameResponse()72 public RecordingGetNameResponse() { 73 reset(); 74 } 75 76 @Override call(String name)77 public void call(String name) { 78 mName = name; 79 mCalled = true; 80 } 81 getName()82 public String getName() { 83 return mName; 84 } 85 wasCalled()86 public boolean wasCalled() { 87 return mCalled; 88 } 89 reset()90 public void reset() { 91 mName = null; 92 mCalled = false; 93 } 94 } 95 96 /** 97 * Basic implementation of {@link Factory}. 98 */ 99 public class MockFactoryImpl extends CapturingErrorHandler implements Factory { 100 101 private boolean mClosed = false; 102 isClosed()103 public boolean isClosed() { 104 return mClosed; 105 } 106 107 /** 108 * @see org.chromium.mojo.bindings.Interface#close() 109 */ 110 @Override close()111 public void close() { 112 mClosed = true; 113 } 114 115 @Override doStuff(Request request, MessagePipeHandle pipe, DoStuffResponse callback)116 public void doStuff(Request request, MessagePipeHandle pipe, DoStuffResponse callback) { 117 if (pipe != null) { 118 pipe.close(); 119 } 120 Response response = new Response(); 121 response.x = 42; 122 callback.call(response, "Hello"); 123 } 124 125 @Override doStuff2(ConsumerHandle pipe, DoStuff2Response callback)126 public void doStuff2(ConsumerHandle pipe, DoStuff2Response callback) { 127 callback.call("World"); 128 } 129 130 @Override createNamedObject(InterfaceRequest<NamedObject> obj)131 public void createNamedObject(InterfaceRequest<NamedObject> obj) { 132 NamedObject.MANAGER.bind(new MockNamedObjectImpl(), obj); 133 } 134 135 @Override requestImportedInterface(InterfaceRequest<ImportedInterface> obj, RequestImportedInterfaceResponse callback)136 public void requestImportedInterface(InterfaceRequest<ImportedInterface> obj, 137 RequestImportedInterfaceResponse callback) { 138 throw new UnsupportedOperationException("Not implemented."); 139 } 140 141 @Override takeImportedInterface(ImportedInterface obj, TakeImportedInterfaceResponse callback)142 public void takeImportedInterface(ImportedInterface obj, 143 TakeImportedInterfaceResponse callback) { 144 throw new UnsupportedOperationException("Not implemented."); 145 } 146 } 147 148 /** 149 * Implementation of DoStuffResponse that keeps track of if the response is called. 150 */ 151 public static class DoStuffResponseImpl implements Factory.DoStuffResponse { 152 private boolean mResponseCalled = false; 153 wasResponseCalled()154 public boolean wasResponseCalled() { 155 return mResponseCalled; 156 } 157 158 @Override call(Response response, String string)159 public void call(Response response, String string) { 160 mResponseCalled = true; 161 } 162 } 163 164 /** 165 * @see MojoTestCase#tearDown() 166 */ 167 @Override tearDown()168 protected void tearDown() throws Exception { 169 // Close the elements in the reverse order they were added. This is needed because it is an 170 // error to close the handle of a proxy without closing the proxy first. 171 Collections.reverse(mCloseablesToClose); 172 for (Closeable c : mCloseablesToClose) { 173 c.close(); 174 } 175 super.tearDown(); 176 } 177 178 /** 179 * Check that the given proxy receives the calls. If |impl| is not null, also check that the 180 * calls are forwared to |impl|. 181 */ checkProxy(NamedObject.Proxy proxy, MockNamedObjectImpl impl)182 private void checkProxy(NamedObject.Proxy proxy, MockNamedObjectImpl impl) { 183 RecordingGetNameResponse callback = new RecordingGetNameResponse(); 184 CapturingErrorHandler errorHandler = new CapturingErrorHandler(); 185 proxy.getProxyHandler().setErrorHandler(errorHandler); 186 187 if (impl != null) { 188 assertNull(impl.getLastMojoException()); 189 assertEquals("", impl.getNameSynchronously()); 190 } 191 192 proxy.getName(callback); 193 runLoopUntilIdle(); 194 195 assertNull(errorHandler.getLastMojoException()); 196 assertTrue(callback.wasCalled()); 197 assertEquals("", callback.getName()); 198 199 callback.reset(); 200 proxy.setName(OBJECT_NAME); 201 runLoopUntilIdle(); 202 203 assertNull(errorHandler.getLastMojoException()); 204 if (impl != null) { 205 assertNull(impl.getLastMojoException()); 206 assertEquals(OBJECT_NAME, impl.getNameSynchronously()); 207 } 208 209 proxy.getName(callback); 210 runLoopUntilIdle(); 211 212 assertNull(errorHandler.getLastMojoException()); 213 assertTrue(callback.wasCalled()); 214 assertEquals(OBJECT_NAME, callback.getName()); 215 } 216 217 @SmallTest testName()218 public void testName() { 219 assertEquals("sample::NamedObject", NamedObject.MANAGER.getName()); 220 } 221 222 @SmallTest testProxyAndStub()223 public void testProxyAndStub() { 224 MockNamedObjectImpl impl = new MockNamedObjectImpl(); 225 NamedObject.Proxy proxy = 226 NamedObject.MANAGER.buildProxy(null, NamedObject.MANAGER.buildStub(null, impl)); 227 228 checkProxy(proxy, impl); 229 } 230 231 @SmallTest testProxyAndStubOverPipe()232 public void testProxyAndStubOverPipe() { 233 MockNamedObjectImpl impl = new MockNamedObjectImpl(); 234 NamedObject.Proxy proxy = 235 BindingsTestUtils.newProxyOverPipe(NamedObject.MANAGER, impl, mCloseablesToClose); 236 237 checkProxy(proxy, impl); 238 } 239 240 @SmallTest testFactoryOverPipe()241 public void testFactoryOverPipe() { 242 Factory.Proxy proxy = BindingsTestUtils.newProxyOverPipe( 243 Factory.MANAGER, new MockFactoryImpl(), mCloseablesToClose); 244 Pair<NamedObject.Proxy, InterfaceRequest<NamedObject>> request = 245 NamedObject.MANAGER.getInterfaceRequest(CoreImpl.getInstance()); 246 mCloseablesToClose.add(request.first); 247 proxy.createNamedObject(request.second); 248 249 checkProxy(request.first, null); 250 } 251 252 @SmallTest testInterfaceClosing()253 public void testInterfaceClosing() { 254 MockFactoryImpl impl = new MockFactoryImpl(); 255 Factory.Proxy proxy = 256 BindingsTestUtils.newProxyOverPipe(Factory.MANAGER, impl, mCloseablesToClose); 257 258 assertFalse(impl.isClosed()); 259 260 proxy.close(); 261 runLoopUntilIdle(); 262 263 assertTrue(impl.isClosed()); 264 } 265 266 @SmallTest testResponse()267 public void testResponse() { 268 MockFactoryImpl impl = new MockFactoryImpl(); 269 Factory.Proxy proxy = 270 BindingsTestUtils.newProxyOverPipe(Factory.MANAGER, impl, mCloseablesToClose); 271 Request request = new Request(); 272 request.x = 42; 273 Pair<MessagePipeHandle, MessagePipeHandle> handles = 274 CoreImpl.getInstance().createMessagePipe(null); 275 DoStuffResponseImpl response = new DoStuffResponseImpl(); 276 proxy.doStuff(request, handles.first, response); 277 278 assertFalse(response.wasResponseCalled()); 279 280 runLoopUntilIdle(); 281 282 assertTrue(response.wasResponseCalled()); 283 } 284 } 285