blob: 5120198feb90dc5f1180f5f36879a141cf14d0dd [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.mojo.system.impl;
import android.support.test.filters.SmallTest;
import org.chromium.mojo.MojoTestCase;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.Core.HandleSignals;
import org.chromium.mojo.system.DataPipe;
import org.chromium.mojo.system.Handle;
import org.chromium.mojo.system.InvalidHandle;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojo.system.MojoResult;
import org.chromium.mojo.system.Pair;
import org.chromium.mojo.system.ResultAnd;
import org.chromium.mojo.system.SharedBufferHandle;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
* Testing the core API.
*/
public class CoreImplTest extends MojoTestCase {
private static final long RUN_LOOP_TIMEOUT_MS = 5;
private static final ScheduledExecutorService WORKER =
Executors.newSingleThreadScheduledExecutor();
private static final HandleSignals ALL_SIGNALS =
HandleSignals.none().setPeerClosed(true).setReadable(true).setWritable(true);
private List<Handle> mHandlesToClose = new ArrayList<Handle>();
/**
* @see MojoTestCase#tearDown()
*/
@Override
protected void tearDown() throws Exception {
MojoException toThrow = null;
for (Handle handle : mHandlesToClose) {
try {
handle.close();
} catch (MojoException e) {
if (toThrow == null) {
toThrow = e;
}
}
}
if (toThrow != null) {
throw toThrow;
}
super.tearDown();
}
private void addHandleToClose(Handle handle) {
mHandlesToClose.add(handle);
}
private void addHandlePairToClose(Pair<? extends Handle, ? extends Handle> handles) {
mHandlesToClose.add(handles.first);
mHandlesToClose.add(handles.second);
}
private static void checkSendingMessage(MessagePipeHandle in, MessagePipeHandle out) {
Random random = new Random();
// Writing a random 8 bytes message.
byte[] bytes = new byte[8];
random.nextBytes(bytes);
ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
buffer.put(bytes);
in.writeMessage(buffer, null, MessagePipeHandle.WriteFlags.NONE);
// Try to read into a small buffer.
ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length / 2);
ResultAnd<MessagePipeHandle.ReadMessageResult> result =
out.readMessage(receiveBuffer, 0, MessagePipeHandle.ReadFlags.NONE);
assertEquals(MojoResult.RESOURCE_EXHAUSTED, result.getMojoResult());
assertEquals(bytes.length, result.getValue().getMessageSize());
assertEquals(0, result.getValue().getHandlesCount());
// Read into a correct buffer.
receiveBuffer = ByteBuffer.allocateDirect(bytes.length);
result = out.readMessage(receiveBuffer, 0, MessagePipeHandle.ReadFlags.NONE);
assertEquals(MojoResult.OK, result.getMojoResult());
assertEquals(bytes.length, result.getValue().getMessageSize());
assertEquals(0, result.getValue().getHandlesCount());
assertEquals(0, receiveBuffer.position());
assertEquals(result.getValue().getMessageSize(), receiveBuffer.limit());
byte[] receivedBytes = new byte[result.getValue().getMessageSize()];
receiveBuffer.get(receivedBytes);
assertTrue(Arrays.equals(bytes, receivedBytes));
}
private static void checkSendingData(DataPipe.ProducerHandle in, DataPipe.ConsumerHandle out) {
Random random = new Random();
// Writing a random 8 bytes message.
byte[] bytes = new byte[8];
random.nextBytes(bytes);
ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
buffer.put(bytes);
ResultAnd<Integer> result = in.writeData(buffer, DataPipe.WriteFlags.NONE);
assertEquals(MojoResult.OK, result.getMojoResult());
assertEquals(bytes.length, result.getValue().intValue());
// Query number of bytes available.
ResultAnd<Integer> readResult = out.readData(null, DataPipe.ReadFlags.none().query(true));
assertEquals(MojoResult.OK, readResult.getMojoResult());
assertEquals(bytes.length, readResult.getValue().intValue());
// Peek data into a buffer.
ByteBuffer peekBuffer = ByteBuffer.allocateDirect(bytes.length);
readResult = out.readData(peekBuffer, DataPipe.ReadFlags.none().peek(true));
assertEquals(MojoResult.OK, readResult.getMojoResult());
assertEquals(bytes.length, readResult.getValue().intValue());
assertEquals(bytes.length, peekBuffer.limit());
byte[] peekBytes = new byte[bytes.length];
peekBuffer.get(peekBytes);
assertTrue(Arrays.equals(bytes, peekBytes));
// Read into a buffer.
ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length);
readResult = out.readData(receiveBuffer, DataPipe.ReadFlags.NONE);
assertEquals(MojoResult.OK, readResult.getMojoResult());
assertEquals(bytes.length, readResult.getValue().intValue());
assertEquals(0, receiveBuffer.position());
assertEquals(bytes.length, receiveBuffer.limit());
byte[] receivedBytes = new byte[bytes.length];
receiveBuffer.get(receivedBytes);
assertTrue(Arrays.equals(bytes, receivedBytes));
}
private static void checkSharing(SharedBufferHandle in, SharedBufferHandle out) {
Random random = new Random();
ByteBuffer buffer1 = in.map(0, 8, SharedBufferHandle.MapFlags.NONE);
assertEquals(8, buffer1.capacity());
ByteBuffer buffer2 = out.map(0, 8, SharedBufferHandle.MapFlags.NONE);
assertEquals(8, buffer2.capacity());
byte[] bytes = new byte[8];
random.nextBytes(bytes);
buffer1.put(bytes);
byte[] receivedBytes = new byte[bytes.length];
buffer2.get(receivedBytes);
assertTrue(Arrays.equals(bytes, receivedBytes));
in.unmap(buffer1);
out.unmap(buffer2);
}
/**
* Testing that Core can be retrieved from a handle.
*/
@SmallTest
public void testGetCore() {
Core core = CoreImpl.getInstance();
Pair<? extends Handle, ? extends Handle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
assertEquals(core, handles.first.getCore());
assertEquals(core, handles.second.getCore());
handles = core.createDataPipe(null);
addHandlePairToClose(handles);
assertEquals(core, handles.first.getCore());
assertEquals(core, handles.second.getCore());
SharedBufferHandle handle = core.createSharedBuffer(null, 100);
SharedBufferHandle handle2 = handle.duplicate(null);
addHandleToClose(handle);
addHandleToClose(handle2);
assertEquals(core, handle.getCore());
assertEquals(core, handle2.getCore());
}
private static void createAndCloseMessagePipe(MessagePipeHandle.CreateOptions options) {
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(options);
handles.first.close();
handles.second.close();
}
/**
* Testing {@link MessagePipeHandle} creation.
*/
@SmallTest
public void testMessagePipeCreation() {
// Test creation with null options.
createAndCloseMessagePipe(null);
// Test creation with default options.
createAndCloseMessagePipe(new MessagePipeHandle.CreateOptions());
}
/**
* Testing {@link MessagePipeHandle}.
*/
@SmallTest
public void testMessagePipeEmpty() {
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
// Testing read on an empty pipe.
ResultAnd<MessagePipeHandle.ReadMessageResult> readResult =
handles.first.readMessage(null, 0, MessagePipeHandle.ReadFlags.NONE);
assertEquals(MojoResult.SHOULD_WAIT, readResult.getMojoResult());
handles.first.close();
handles.second.close();
}
/**
* Testing {@link MessagePipeHandle}.
*/
@SmallTest
public void testMessagePipeSend() {
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
checkSendingMessage(handles.first, handles.second);
checkSendingMessage(handles.second, handles.first);
}
/**
* Testing {@link MessagePipeHandle}.
*/
@SmallTest
public void testMessagePipeReceiveOnSmallBuffer() {
Random random = new Random();
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
// Writing a random 8 bytes message.
byte[] bytes = new byte[8];
random.nextBytes(bytes);
ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
buffer.put(bytes);
handles.first.writeMessage(buffer, null, MessagePipeHandle.WriteFlags.NONE);
ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(1);
ResultAnd<MessagePipeHandle.ReadMessageResult> result =
handles.second.readMessage(receiveBuffer, 0, MessagePipeHandle.ReadFlags.NONE);
assertEquals(MojoResult.RESOURCE_EXHAUSTED, result.getMojoResult());
assertEquals(bytes.length, result.getValue().getMessageSize());
assertEquals(0, result.getValue().getHandlesCount());
}
/**
* Testing {@link MessagePipeHandle}.
*/
@SmallTest
public void testMessagePipeSendHandles() {
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
Pair<MessagePipeHandle, MessagePipeHandle> handlesToShare = core.createMessagePipe(null);
addHandlePairToClose(handles);
addHandlePairToClose(handlesToShare);
handles.first.writeMessage(null, Collections.<Handle>singletonList(handlesToShare.second),
MessagePipeHandle.WriteFlags.NONE);
assertFalse(handlesToShare.second.isValid());
ResultAnd<MessagePipeHandle.ReadMessageResult> readMessageResult =
handles.second.readMessage(null, 1, MessagePipeHandle.ReadFlags.NONE);
assertEquals(1, readMessageResult.getValue().getHandlesCount());
MessagePipeHandle newHandle =
readMessageResult.getValue().getHandles().get(0).toMessagePipeHandle();
addHandleToClose(newHandle);
assertTrue(newHandle.isValid());
checkSendingMessage(handlesToShare.first, newHandle);
checkSendingMessage(newHandle, handlesToShare.first);
}
private static void createAndCloseDataPipe(DataPipe.CreateOptions options) {
Core core = CoreImpl.getInstance();
Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles =
core.createDataPipe(options);
handles.first.close();
handles.second.close();
}
/**
* Testing {@link DataPipe}.
*/
@SmallTest
public void testDataPipeCreation() {
// Create datapipe with null options.
createAndCloseDataPipe(null);
DataPipe.CreateOptions options = new DataPipe.CreateOptions();
// Create datapipe with element size set.
options.setElementNumBytes(24);
createAndCloseDataPipe(options);
// Create datapipe with capacity set.
options.setCapacityNumBytes(1024 * options.getElementNumBytes());
createAndCloseDataPipe(options);
}
/**
* Testing {@link DataPipe}.
*/
@SmallTest
public void testDataPipeSend() {
Core core = CoreImpl.getInstance();
Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
addHandlePairToClose(handles);
checkSendingData(handles.first, handles.second);
}
/**
* Testing {@link DataPipe}.
*/
@SmallTest
public void testDataPipeTwoPhaseSend() {
Random random = new Random();
Core core = CoreImpl.getInstance();
Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
addHandlePairToClose(handles);
// Writing a random 8 bytes message.
byte[] bytes = new byte[8];
random.nextBytes(bytes);
ByteBuffer buffer = handles.first.beginWriteData(bytes.length, DataPipe.WriteFlags.NONE);
assertTrue(buffer.capacity() >= bytes.length);
buffer.put(bytes);
handles.first.endWriteData(bytes.length);
// Read into a buffer.
ByteBuffer receiveBuffer =
handles.second.beginReadData(bytes.length, DataPipe.ReadFlags.NONE);
assertEquals(0, receiveBuffer.position());
assertEquals(bytes.length, receiveBuffer.limit());
byte[] receivedBytes = new byte[bytes.length];
receiveBuffer.get(receivedBytes);
assertTrue(Arrays.equals(bytes, receivedBytes));
handles.second.endReadData(bytes.length);
}
/**
* Testing {@link DataPipe}.
*/
@SmallTest
public void testDataPipeDiscard() {
Random random = new Random();
Core core = CoreImpl.getInstance();
Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
addHandlePairToClose(handles);
// Writing a random 8 bytes message.
byte[] bytes = new byte[8];
random.nextBytes(bytes);
ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
buffer.put(bytes);
ResultAnd<Integer> result = handles.first.writeData(buffer, DataPipe.WriteFlags.NONE);
assertEquals(MojoResult.OK, result.getMojoResult());
assertEquals(bytes.length, result.getValue().intValue());
// Discard bytes.
final int nbBytesToDiscard = 4;
assertEquals(nbBytesToDiscard,
handles.second.discardData(nbBytesToDiscard, DataPipe.ReadFlags.NONE));
// Read into a buffer.
ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length - nbBytesToDiscard);
ResultAnd<Integer> readResult =
handles.second.readData(receiveBuffer, DataPipe.ReadFlags.NONE);
assertEquals(MojoResult.OK, readResult.getMojoResult());
assertEquals(bytes.length - nbBytesToDiscard, readResult.getValue().intValue());
assertEquals(0, receiveBuffer.position());
assertEquals(bytes.length - nbBytesToDiscard, receiveBuffer.limit());
byte[] receivedBytes = new byte[bytes.length - nbBytesToDiscard];
receiveBuffer.get(receivedBytes);
assertTrue(Arrays.equals(
Arrays.copyOfRange(bytes, nbBytesToDiscard, bytes.length), receivedBytes));
}
/**
* Testing {@link SharedBufferHandle}.
*/
@SmallTest
public void testSharedBufferCreation() {
Core core = CoreImpl.getInstance();
// Test creation with empty options.
core.createSharedBuffer(null, 8).close();
// Test creation with default options.
core.createSharedBuffer(new SharedBufferHandle.CreateOptions(), 8).close();
}
/**
* Testing {@link SharedBufferHandle}.
*/
@SmallTest
public void testSharedBufferDuplication() {
Core core = CoreImpl.getInstance();
SharedBufferHandle handle = core.createSharedBuffer(null, 8);
addHandleToClose(handle);
// Test duplication with empty options.
handle.duplicate(null).close();
// Test creation with default options.
handle.duplicate(new SharedBufferHandle.DuplicateOptions()).close();
}
/**
* Testing {@link SharedBufferHandle}.
*/
@SmallTest
public void testSharedBufferSending() {
Core core = CoreImpl.getInstance();
SharedBufferHandle handle = core.createSharedBuffer(null, 8);
addHandleToClose(handle);
SharedBufferHandle newHandle = handle.duplicate(null);
addHandleToClose(newHandle);
checkSharing(handle, newHandle);
checkSharing(newHandle, handle);
}
/**
* Testing that invalid handle can be used with this implementation.
*/
@SmallTest
public void testInvalidHandle() {
Core core = CoreImpl.getInstance();
Handle handle = InvalidHandle.INSTANCE;
// Checking sending an invalid handle.
// Until the behavior is changed on the C++ side, handle gracefully 2 different use case:
// - Receive a INVALID_ARGUMENT exception
// - Receive an invalid handle on the other side.
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
try {
handles.first.writeMessage(null, Collections.<Handle>singletonList(handle),
MessagePipeHandle.WriteFlags.NONE);
ResultAnd<MessagePipeHandle.ReadMessageResult> readMessageResult =
handles.second.readMessage(null, 1, MessagePipeHandle.ReadFlags.NONE);
assertEquals(1, readMessageResult.getValue().getHandlesCount());
assertFalse(readMessageResult.getValue().getHandles().get(0).isValid());
} catch (MojoException e) {
assertEquals(MojoResult.INVALID_ARGUMENT, e.getMojoResult());
}
}
/**
* Testing the pass method on message pipes.
*/
@SmallTest
public void testMessagePipeHandlePass() {
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
assertTrue(handles.first.isValid());
MessagePipeHandle handleClone = handles.first.pass();
addHandleToClose(handleClone);
assertFalse(handles.first.isValid());
assertTrue(handleClone.isValid());
checkSendingMessage(handleClone, handles.second);
checkSendingMessage(handles.second, handleClone);
}
/**
* Testing the pass method on data pipes.
*/
@SmallTest
public void testDataPipeHandlePass() {
Core core = CoreImpl.getInstance();
Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null);
addHandlePairToClose(handles);
DataPipe.ProducerHandle producerClone = handles.first.pass();
DataPipe.ConsumerHandle consumerClone = handles.second.pass();
addHandleToClose(producerClone);
addHandleToClose(consumerClone);
assertFalse(handles.first.isValid());
assertFalse(handles.second.isValid());
assertTrue(producerClone.isValid());
assertTrue(consumerClone.isValid());
checkSendingData(producerClone, consumerClone);
}
/**
* Testing the pass method on shared buffers.
*/
@SmallTest
public void testSharedBufferPass() {
Core core = CoreImpl.getInstance();
SharedBufferHandle handle = core.createSharedBuffer(null, 8);
addHandleToClose(handle);
SharedBufferHandle newHandle = handle.duplicate(null);
addHandleToClose(newHandle);
SharedBufferHandle handleClone = handle.pass();
SharedBufferHandle newHandleClone = newHandle.pass();
addHandleToClose(handleClone);
addHandleToClose(newHandleClone);
assertFalse(handle.isValid());
assertTrue(handleClone.isValid());
checkSharing(handleClone, newHandleClone);
checkSharing(newHandleClone, handleClone);
}
/**
* esting handle conversion to native and back.
*/
@SmallTest
public void testHandleConversion() {
Core core = CoreImpl.getInstance();
Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null);
addHandlePairToClose(handles);
MessagePipeHandle converted =
core.acquireNativeHandle(handles.first.releaseNativeHandle()).toMessagePipeHandle();
addHandleToClose(converted);
assertFalse(handles.first.isValid());
checkSendingMessage(converted, handles.second);
checkSendingMessage(handles.second, converted);
}
}