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.
5 package org.chromium.mojo.system;
7 import android.content.Context;
8 import android.test.InstrumentationTestCase;
9 import android.test.suitebuilder.annotation.SmallTest;
11 import org.chromium.base.JNINamespace;
12 import org.chromium.base.library_loader.LibraryLoader;
13 import org.chromium.mojo.system.Core.WaitFlags;
14 import org.chromium.mojo.system.Core.WaitManyResult;
15 import org.chromium.mojo.system.MessagePipeHandle.ReadFlags;
16 import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
17 import org.chromium.mojo.system.MessagePipeHandle.WriteFlags;
18 import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
20 import java.nio.ByteBuffer;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Random;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.ScheduledExecutorService;
28 import java.util.concurrent.TimeUnit;
31 * Testing the core API.
33 @JNINamespace("mojo::android")
34 public class CoreTest extends InstrumentationTestCase {
36 private static final ScheduledExecutorService WORKER =
37 Executors.newSingleThreadScheduledExecutor();
40 * @see junit.framework.TestCase#setUp()
43 protected void setUp() throws Exception {
44 LibraryLoader.ensureInitialized();
45 nativeInitApplicationContext(getInstrumentation().getTargetContext());
49 * Runnable that will close the given handle.
51 private static class CloseHandle implements Runnable {
52 private Handle mHandle;
54 CloseHandle(Handle handle) {
64 private static void checkSendingMessage(MessagePipeHandle in, MessagePipeHandle out) {
65 Random random = new Random();
67 // Writing a random 8 bytes message.
68 byte[] bytes = new byte[8];
69 random.nextBytes(bytes);
70 ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
72 in.writeMessage(buffer, null, MessagePipeHandle.WriteFlags.none());
74 // Try to read into a small buffer.
75 ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length / 2);
76 MessagePipeHandle.ReadMessageResult result = out.readMessage(receiveBuffer, 0,
77 MessagePipeHandle.ReadFlags.none());
78 assertFalse(result.getWasMessageRead());
79 assertEquals(bytes.length, result.getMessageSize());
80 assertEquals(0, result.getHandlesCount());
82 // Read into a correct buffer.
83 receiveBuffer = ByteBuffer.allocateDirect(bytes.length);
84 result = out.readMessage(receiveBuffer, 0,
85 MessagePipeHandle.ReadFlags.none());
86 assertTrue(result.getWasMessageRead());
87 assertEquals(bytes.length, result.getMessageSize());
88 assertEquals(0, result.getHandlesCount());
89 assertEquals(0, receiveBuffer.position());
90 assertEquals(result.getMessageSize(), receiveBuffer.limit());
91 byte[] receivedBytes = new byte[result.getMessageSize()];
92 receiveBuffer.get(receivedBytes);
93 assertTrue(Arrays.equals(bytes, receivedBytes));
98 * Testing {@link Core#waitMany(List, long)}.
101 public void testWaitMany() {
102 Core core = CoreImpl.getInstance();
103 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
106 List<Pair<Handle, WaitFlags>> handlesToWaitOn = new ArrayList<
107 Pair<Handle, WaitFlags>>();
110 new Pair<Handle, WaitFlags>(handles.second,
111 WaitFlags.none().setReadable(true)));
113 new Pair<Handle, WaitFlags>(handles.first, WaitFlags.none().setWritable(true)));
114 WaitManyResult result = core.waitMany(handlesToWaitOn, 0);
115 assertEquals(MojoResult.OK, result.getMojoResult());
116 assertEquals(1, result.getHandleIndex());
118 handlesToWaitOn.clear();
120 new Pair<Handle, WaitFlags>(handles.first, WaitFlags.none().setWritable(true)));
122 new Pair<Handle, WaitFlags>(handles.second,
123 WaitFlags.none().setReadable(true)));
124 result = core.waitMany(handlesToWaitOn, 0);
125 assertEquals(MojoResult.OK, result.getMojoResult());
126 assertEquals(0, result.getHandleIndex());
128 handles.first.close();
129 handles.second.close();
134 * Testing {@link MessagePipeHandle}.
137 public void testMessagePipeEmpty() {
138 Core core = CoreImpl.getInstance();
139 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
143 assertEquals(MojoResult.OK, handles.first.wait(WaitFlags.all(), 0));
144 assertEquals(MojoResult.OK, handles.first.wait(WaitFlags.none().setWritable(true), 0));
145 assertEquals(MojoResult.DEADLINE_EXCEEDED,
146 handles.first.wait(WaitFlags.none().setReadable(true), 0));
148 // Testing read on an empty pipe.
149 boolean exception = false;
151 handles.first.readMessage(null, 0, MessagePipeHandle.ReadFlags.none());
152 } catch (MojoException e) {
153 assertEquals(MojoResult.SHOULD_WAIT, e.getMojoResult());
156 assertTrue(exception);
158 // Closing a pipe while waiting.
159 WORKER.schedule(new CloseHandle(handles.first), 10, TimeUnit.MILLISECONDS);
160 assertEquals(MojoResult.CANCELLED,
161 handles.first.wait(WaitFlags.none().setReadable(true), 1000000L));
163 handles.first.close();
164 handles.second.close();
167 handles = core.createMessagePipe();
170 // Closing the other pipe while waiting.
171 WORKER.schedule(new CloseHandle(handles.first), 10, TimeUnit.MILLISECONDS);
172 assertEquals(MojoResult.FAILED_PRECONDITION,
173 handles.second.wait(WaitFlags.none().setReadable(true), 1000000L));
175 // Waiting on a closed pipe.
176 assertEquals(MojoResult.FAILED_PRECONDITION,
177 handles.second.wait(WaitFlags.none().setReadable(true), 0));
178 assertEquals(MojoResult.FAILED_PRECONDITION,
179 handles.second.wait(WaitFlags.none().setWritable(true), 0));
181 handles.first.close();
182 handles.second.close();
188 * Testing {@link MessagePipeHandle}.
191 public void testMessagePipeSend() {
192 Core core = CoreImpl.getInstance();
193 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
196 checkSendingMessage(handles.first, handles.second);
197 checkSendingMessage(handles.second, handles.first);
199 handles.first.close();
200 handles.second.close();
205 * Testing {@link MessagePipeHandle}.
208 public void testMessagePipeReceiveOnSmallBuffer() {
209 Random random = new Random();
210 Core core = CoreImpl.getInstance();
211 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
214 // Writing a random 8 bytes message.
215 byte[] bytes = new byte[8];
216 random.nextBytes(bytes);
217 ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
219 handles.first.writeMessage(buffer, null, MessagePipeHandle.WriteFlags.none());
221 ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(1);
222 MessagePipeHandle.ReadMessageResult result = handles.second.readMessage(receiveBuffer,
224 MessagePipeHandle.ReadFlags.none());
225 assertFalse(result.getWasMessageRead());
226 assertEquals(bytes.length, result.getMessageSize());
227 assertEquals(0, result.getHandlesCount());
229 handles.first.close();
230 handles.second.close();
235 * Testing {@link MessagePipeHandle}.
238 public void testMessagePipeSendHandles() {
239 Core core = CoreImpl.getInstance();
240 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
241 Pair<MessagePipeHandle, MessagePipeHandle> handlesToShare = core.createMessagePipe();
244 handles.first.writeMessage(null,
245 Collections.<Handle> singletonList(handlesToShare.second),
247 assertFalse(handlesToShare.second.isValid());
248 ReadMessageResult readMessageResult = handles.second.readMessage(null, 1,
250 assertEquals(1, readMessageResult.getHandlesCount());
251 MessagePipeHandle newHandle = readMessageResult.getHandles().get(0)
252 .toMessagePipeHandle();
254 assertTrue(newHandle.isValid());
255 checkSendingMessage(handlesToShare.first, newHandle);
256 checkSendingMessage(newHandle, handlesToShare.first);
261 handles.first.close();
262 handles.second.close();
263 handlesToShare.first.close();
264 handlesToShare.second.close();
268 private static void createAndCloseDataPipe(DataPipe.CreateOptions options) {
269 Core core = CoreImpl.getInstance();
270 Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(
272 handles.first.close();
273 handles.second.close();
277 * Testing {@link DataPipe}.
280 public void testDataPipeCreation() {
281 // Create datapipe with null options.
282 createAndCloseDataPipe(null);
283 DataPipe.CreateOptions options = new DataPipe.CreateOptions();
284 // Create datapipe with element size set.
285 options.setElementNumBytes(24);
286 createAndCloseDataPipe(options);
287 // Create datapipe with a flag set.
288 options.getFlags().setMayDiscard(true);
289 createAndCloseDataPipe(options);
290 // Create datapipe with capacity set.
291 options.setCapacityNumBytes(1024 * options.getElementNumBytes());
292 createAndCloseDataPipe(options);
296 * Testing {@link DataPipe}.
299 public void testDataPipeSend() {
300 Core core = CoreImpl.getInstance();
301 Random random = new Random();
303 Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
305 // Writing a random 8 bytes message.
306 byte[] bytes = new byte[8];
307 random.nextBytes(bytes);
308 ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
310 int result = handles.first.writeData(buffer, DataPipe.WriteFlags.none());
311 assertEquals(bytes.length, result);
313 // Query number of bytes available.
314 result = handles.second.readData(null,
315 DataPipe.ReadFlags.none().query(true));
316 assertEquals(bytes.length, result);
318 // Read into a buffer.
319 ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length);
320 result = handles.second.readData(receiveBuffer,
321 DataPipe.ReadFlags.none());
322 assertEquals(bytes.length, result);
323 assertEquals(0, receiveBuffer.position());
324 assertEquals(bytes.length, receiveBuffer.limit());
325 byte[] receivedBytes = new byte[bytes.length];
326 receiveBuffer.get(receivedBytes);
327 assertTrue(Arrays.equals(bytes, receivedBytes));
329 handles.first.close();
330 handles.second.close();
335 * Testing {@link DataPipe}.
338 public void testDataPipeTwoPhaseSend() {
339 Random random = new Random();
340 Core core = CoreImpl.getInstance();
341 Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
344 // Writing a random 8 bytes message.
345 byte[] bytes = new byte[8];
346 random.nextBytes(bytes);
347 ByteBuffer buffer = handles.first.beginWriteData(bytes.length,
348 DataPipe.WriteFlags.none());
349 assertTrue(buffer.capacity() >= bytes.length);
351 handles.first.endWriteData(bytes.length);
353 // Read into a buffer.
354 ByteBuffer receiveBuffer = handles.second.beginReadData(bytes.length,
355 DataPipe.ReadFlags.none());
356 assertEquals(0, receiveBuffer.position());
357 assertEquals(bytes.length, receiveBuffer.limit());
358 byte[] receivedBytes = new byte[bytes.length];
359 receiveBuffer.get(receivedBytes);
360 assertTrue(Arrays.equals(bytes, receivedBytes));
361 handles.second.endReadData(bytes.length);
363 handles.first.close();
364 handles.second.close();
369 * Testing {@link DataPipe}.
372 public void testDataPipeDiscard() {
373 Random random = new Random();
374 Core core = CoreImpl.getInstance();
375 Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
378 // Writing a random 8 bytes message.
379 byte[] bytes = new byte[8];
380 random.nextBytes(bytes);
381 ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
383 int result = handles.first.writeData(buffer, DataPipe.WriteFlags.none());
384 assertEquals(bytes.length, result);
387 final int nbBytesToDiscard = 4;
388 assertEquals(nbBytesToDiscard,
389 handles.second.discardData(nbBytesToDiscard, DataPipe.ReadFlags.none()));
391 // Read into a buffer.
392 ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length - nbBytesToDiscard);
393 result = handles.second.readData(receiveBuffer,
394 DataPipe.ReadFlags.none());
395 assertEquals(bytes.length - nbBytesToDiscard, result);
396 assertEquals(0, receiveBuffer.position());
397 assertEquals(bytes.length - nbBytesToDiscard, receiveBuffer.limit());
398 byte[] receivedBytes = new byte[bytes.length - nbBytesToDiscard];
399 receiveBuffer.get(receivedBytes);
400 assertTrue(Arrays.equals(Arrays.copyOfRange(bytes, nbBytesToDiscard, bytes.length),
403 handles.first.close();
404 handles.second.close();
409 * Testing {@link SharedBufferHandle}.
412 public void testSharedBufferCreation() {
413 Core core = CoreImpl.getInstance();
414 // Test creation with empty options.
415 core.createSharedBuffer(null, 8).close();
416 // Test creation with default options.
417 core.createSharedBuffer(new SharedBufferHandle.CreateOptions(), 8);
421 * Testing {@link SharedBufferHandle}.
424 public void testSharedBufferDuplication() {
425 Core core = CoreImpl.getInstance();
426 SharedBufferHandle handle = core.createSharedBuffer(null, 8);
428 // Test duplication with empty options.
429 handle.duplicate(null).close();
430 // Test creation with default options.
431 handle.duplicate(new SharedBufferHandle.DuplicateOptions()).close();
438 * Testing {@link SharedBufferHandle}.
441 public void testSharedBufferSending() {
442 Random random = new Random();
443 Core core = CoreImpl.getInstance();
444 SharedBufferHandle handle = core.createSharedBuffer(null, 8);
445 SharedBufferHandle newHandle = handle.duplicate(null);
448 ByteBuffer buffer1 = handle.map(0, 8, MapFlags.none());
449 assertEquals(8, buffer1.capacity());
450 ByteBuffer buffer2 = newHandle.map(0, 8, MapFlags.none());
451 assertEquals(8, buffer2.capacity());
453 byte[] bytes = new byte[8];
454 random.nextBytes(bytes);
457 byte[] receivedBytes = new byte[bytes.length];
458 buffer2.get(receivedBytes);
460 assertTrue(Arrays.equals(bytes, receivedBytes));
462 handle.unmap(buffer1);
463 newHandle.unmap(buffer2);
471 * Testing that invalid handle can be used with this implementation.
474 public void testInvalidHandle() {
475 Core core = CoreImpl.getInstance();
476 Handle handle = new InvalidHandle();
479 boolean exception = false;
481 core.wait(handle, WaitFlags.all(), 0);
482 } catch (MojoException e) {
483 assertEquals(MojoResult.INVALID_ARGUMENT, e.getMojoResult());
486 assertTrue(exception);
488 // Checking waitMany.
491 List<Pair<Handle, WaitFlags>> handles = new ArrayList<Pair<Handle, WaitFlags>>();
492 handles.add(Pair.create(handle, WaitFlags.all()));
493 core.waitMany(handles, 0);
494 } catch (MojoException e) {
495 assertEquals(MojoResult.INVALID_ARGUMENT, e.getMojoResult());
498 assertTrue(exception);
500 // Checking sending an invalid handle.
501 // Until the behavior is changed on the C++ side, handle gracefully 2 different use case:
502 // - Receive a INVALID_ARGUMENT exception
503 // - Receive an invalid handle on the other side.
504 Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe();
506 handles.first.writeMessage(null,
507 Collections.<Handle> singletonList(handle),
509 ReadMessageResult readMessageResult = handles.second.readMessage(null, 1,
511 assertEquals(1, readMessageResult.getHandlesCount());
512 assertFalse(readMessageResult.getHandles().get(0).isValid());
513 } catch (MojoException e) {
514 assertEquals(MojoResult.INVALID_ARGUMENT, e.getMojoResult());
516 handles.first.close();
517 handles.second.close();
521 private native void nativeInitApplicationContext(Context context);