blob: 77b80fe6363e8e85fa6dc91cbda438f58d652671 [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 tests
import (
"bytes"
"testing"
"mojo/public/go/system"
)
const (
MOJO_HANDLE_SIGNAL_READWRITABLE = system.MojoHandleSignals(system.MOJO_HANDLE_SIGNAL_READABLE |
system.MOJO_HANDLE_SIGNAL_WRITABLE)
MOJO_HANDLE_SIGNAL_ALL = system.MojoHandleSignals(system.MOJO_HANDLE_SIGNAL_READABLE |
system.MOJO_HANDLE_SIGNAL_WRITABLE |
system.MOJO_HANDLE_SIGNAL_PEER_CLOSED)
)
func TestGetTimeTicksNow(t *testing.T) {
x := core.GetTimeTicksNow()
if x < 10 {
t.Error("Invalid GetTimeTicksNow return value")
}
}
func TestHandle(t *testing.T) {
var handle system.SharedBufferHandle
var r system.MojoResult
if r, handle = core.CreateSharedBuffer(nil, 1); r != system.MOJO_RESULT_OK {
t.Fatalf("CreateSharedBuffer failed:%v", r)
}
if !handle.IsValid() {
t.Fatalf("CreateSharedBuffer returned invalid handle:%v", handle)
}
duplicate := handle
if duplicate.NativeHandle() != handle.NativeHandle() {
t.Fatalf("duplicate(%v) and handle(%v) point to different handles", duplicate.NativeHandle(), handle.NativeHandle())
}
releasedHandle := handle.ReleaseNativeHandle()
if duplicate.IsValid() || handle.IsValid() {
t.Fatalf("duplicate(%v) and handle(%v) should be invalid after releasing native handle", duplicate.NativeHandle(), handle.NativeHandle())
}
handle = core.AcquireNativeHandle(releasedHandle).ToSharedBufferHandle()
if handle.NativeHandle() != releasedHandle || !handle.IsValid() {
t.Fatalf("handle(%v) should be valid after AcquireNativeHandle", handle.NativeHandle())
}
untypedHandle := handle.ToUntypedHandle()
if handle.IsValid() {
t.Fatalf("handle(%v) should be invalid after call ToUntypedHandle", handle.NativeHandle())
}
handle = untypedHandle.ToSharedBufferHandle()
if untypedHandle.IsValid() {
t.Fatalf("untypedHandle(%v) should be invalid after call ToSharedBufferHandle", untypedHandle.NativeHandle())
}
if handle.NativeHandle() != releasedHandle {
t.Fatalf("handle(%v) should be wrapping %v", handle.NativeHandle(), releasedHandle)
}
if r = handle.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on handle failed:%v", r)
}
}
func TestMessagePipe(t *testing.T) {
var h0, h1 system.MessagePipeHandle
var r system.MojoResult
var state system.MojoHandleSignalsState
if r, h0, h1 = core.CreateMessagePipe(nil); r != system.MOJO_RESULT_OK {
t.Fatalf("CreateMessagePipe failed:%v", r)
}
if !h0.IsValid() || !h1.IsValid() {
t.Fatalf("CreateMessagePipe returned invalid handles h0:%v h1:%v", h0, h1)
}
r, state = h0.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, 0)
if r != system.MOJO_RESULT_DEADLINE_EXCEEDED {
t.Fatalf("h0 should not be readable:%v", r)
}
if state.SatisfiedSignals != system.MOJO_HANDLE_SIGNAL_WRITABLE {
t.Fatalf("state should be not be signaled readable after CreateMessagePipe:%v", state.SatisfiedSignals)
}
if state.SatisfiableSignals != MOJO_HANDLE_SIGNAL_ALL {
t.Fatalf("state should allow all signals after CreateMessagePipe:%v", state.SatisfiableSignals)
}
r, state = h0.Wait(system.MOJO_HANDLE_SIGNAL_WRITABLE, system.MOJO_DEADLINE_INDEFINITE)
if r != system.MOJO_RESULT_OK {
t.Fatalf("h0 should be writable:%v", r)
}
if state.SatisfiedSignals != system.MOJO_HANDLE_SIGNAL_WRITABLE {
t.Fatalf("state should be signaled writable after core.Wait:%v", state.SatisfiedSignals)
}
if state.SatisfiableSignals != MOJO_HANDLE_SIGNAL_ALL {
t.Fatalf("state should allow all signals after core.Wait:%v", state.SatisfiableSignals)
}
if r, _, _ = h0.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE); r != system.MOJO_RESULT_SHOULD_WAIT {
t.Fatalf("Read on h0 did not return wait:%v", r)
}
kHello := []byte("hello")
if r = h1.WriteMessage(kHello, nil, system.MOJO_WRITE_MESSAGE_FLAG_NONE); r != system.MOJO_RESULT_OK {
t.Fatalf("Failed WriteMessage on h1:%v", r)
}
r, state = h0.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, system.MOJO_DEADLINE_INDEFINITE)
if r != system.MOJO_RESULT_OK {
t.Fatalf("h0 should be readable after WriteMessage to h1:%v", r)
}
if state.SatisfiedSignals != MOJO_HANDLE_SIGNAL_READWRITABLE {
t.Fatalf("h0 should be signaled readable after WriteMessage to h1:%v", state.SatisfiedSignals)
}
if state.SatisfiableSignals != MOJO_HANDLE_SIGNAL_ALL {
t.Fatalf("h0 should be readable/writable after WriteMessage to h1:%v", state.SatisfiableSignals)
}
if !state.SatisfiableSignals.IsReadable() || !state.SatisfiableSignals.IsWritable() || !state.SatisfiableSignals.IsClosed() {
t.Fatalf("Helper functions are misbehaving")
}
r, msg, _ := h0.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE)
if r != system.MOJO_RESULT_OK {
t.Fatalf("Failed ReadMessage on h0:%v", r)
}
if !bytes.Equal(msg, kHello) {
t.Fatalf("Invalid message expected:%s, got:%s", kHello, msg)
}
r, index, states := core.WaitMany([]system.Handle{h0}, []system.MojoHandleSignals{system.MOJO_HANDLE_SIGNAL_READABLE}, 10)
if r != system.MOJO_RESULT_DEADLINE_EXCEEDED {
t.Fatalf("h0 should not be readable after reading message:%v", r)
}
if index != -1 {
t.Fatalf("should be no index after MOJO_RESULT_DEADLINE_EXCEEDED:%v", index)
}
if len(states) != 1 {
t.Fatalf("states should be set after WaitMany:%v", states)
}
if states[0].SatisfiedSignals != system.MOJO_HANDLE_SIGNAL_WRITABLE {
t.Fatalf("h0 should be signaled readable WaitMany:%v", states[0].SatisfiedSignals)
}
if states[0].SatisfiableSignals != MOJO_HANDLE_SIGNAL_ALL {
t.Fatalf("h0 should be readable/writable after WaitMany:%v", states[0].SatisfiableSignals)
}
if r = h0.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on h0 failed:%v", r)
}
r, state = h1.Wait(MOJO_HANDLE_SIGNAL_READWRITABLE, system.MOJO_DEADLINE_INDEFINITE)
if r != system.MOJO_RESULT_FAILED_PRECONDITION {
t.Fatalf("h1 should not be readable/writable after Close(h0):%v", r)
}
if state.SatisfiedSignals != system.MOJO_HANDLE_SIGNAL_PEER_CLOSED {
t.Fatalf("state should be signaled closed after Close(h0):%v", state.SatisfiedSignals)
}
if state.SatisfiableSignals != system.MOJO_HANDLE_SIGNAL_PEER_CLOSED {
t.Fatalf("state should only be closable after Close(h0):%v", state.SatisfiableSignals)
}
if r = h1.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on h1 failed:%v", r)
}
}
func TestDataPipe(t *testing.T) {
var hp system.ProducerHandle
var hc system.ConsumerHandle
var r system.MojoResult
if r, hp, hc = core.CreateDataPipe(nil); r != system.MOJO_RESULT_OK {
t.Fatalf("CreateDataPipe failed:%v", r)
}
if !hp.IsValid() || !hc.IsValid() {
t.Fatalf("CreateDataPipe returned invalid handles hp:%v hc:%v", hp, hc)
}
if r, _ = hc.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, 0); r != system.MOJO_RESULT_DEADLINE_EXCEEDED {
t.Fatalf("hc should not be readable:%v", r)
}
if r, _ = hp.Wait(system.MOJO_HANDLE_SIGNAL_WRITABLE, system.MOJO_DEADLINE_INDEFINITE); r != system.MOJO_RESULT_OK {
t.Fatalf("hp should be writeable:%v", r)
}
// Test one-phase read/write.
// Writing.
kHello := []byte("hello")
r, numBytes := hp.WriteData(kHello, system.MOJO_WRITE_DATA_FLAG_NONE)
if r != system.MOJO_RESULT_OK || numBytes != len(kHello) {
t.Fatalf("Failed WriteData on hp:%v numBytes:%d", r, numBytes)
}
// Reading.
if r, _ = hc.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, system.MOJO_DEADLINE_INDEFINITE); r != system.MOJO_RESULT_OK {
t.Fatalf("hc should be readable after WriteData on hp:%v", r)
}
r, data := hc.ReadData(system.MOJO_READ_DATA_FLAG_NONE)
if r != system.MOJO_RESULT_OK {
t.Fatalf("Failed ReadData on hc:%v", r)
}
if !bytes.Equal(data, kHello) {
t.Fatalf("Invalid data expected:%s, got:%s", kHello, data)
}
// Test two-phase read/write.
// Writing.
kHello = []byte("Hello, world!")
r, buf := hp.BeginWriteData(len(kHello), system.MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)
if r != system.MOJO_RESULT_OK {
t.Fatalf("Failed BeginWriteData on hp:%v numBytes:%d", r, len(kHello))
}
if len(buf) < len(kHello) {
t.Fatalf("Buffer size(%d) should be at least %d", len(buf), len(kHello))
}
copy(buf, kHello)
if r, _ := hp.WriteData(kHello, system.MOJO_WRITE_DATA_FLAG_NONE); r != system.MOJO_RESULT_BUSY {
t.Fatalf("hp should be busy during a two-phase write: %v", r)
}
if r, _ = hc.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, 0); r != system.MOJO_RESULT_DEADLINE_EXCEEDED {
t.Fatalf("hc shouldn't be readable before EndWriteData on hp:%v", r)
}
if r := hp.EndWriteData(len(kHello)); r != system.MOJO_RESULT_OK {
t.Fatalf("Failed EndWriteData on hp:%v", r)
}
// Reading.
if r, _ = hc.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, system.MOJO_DEADLINE_INDEFINITE); r != system.MOJO_RESULT_OK {
t.Fatalf("hc should be readable after EndWriteData on hp:%v", r)
}
if r, buf = hc.BeginReadData(len(kHello), system.MOJO_READ_DATA_FLAG_ALL_OR_NONE); r != system.MOJO_RESULT_OK {
t.Fatalf("Failed BeginReadData on hc:%v numBytes:%d", r, len(kHello))
}
if len(buf) != len(kHello) {
t.Fatalf("Buffer size(%d) should be equal to %d", len(buf), len(kHello))
}
if r, _ := hc.ReadData(system.MOJO_READ_DATA_FLAG_NONE); r != system.MOJO_RESULT_BUSY {
t.Fatalf("hc should be busy during a two-phase read: %v", r)
}
if !bytes.Equal(buf, kHello) {
t.Fatalf("Invalid data expected:%s, got:%s", kHello, buf)
}
if r := hc.EndReadData(len(buf)); r != system.MOJO_RESULT_OK {
t.Fatalf("Failed EndReadData on hc:%v", r)
}
if r = hp.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on hp failed:%v", r)
}
if r, _ = hc.Wait(system.MOJO_HANDLE_SIGNAL_READABLE, system.MOJO_DEADLINE_INDEFINITE); r != system.MOJO_RESULT_FAILED_PRECONDITION {
t.Fatalf("hc should not be readable after hp closed:%v", r)
}
if r = hc.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on hc failed:%v", r)
}
}
func TestSharedBuffer(t *testing.T) {
var h0, h1 system.SharedBufferHandle
var buf []byte
var r system.MojoResult
if r, h0 = core.CreateSharedBuffer(nil, 100); r != system.MOJO_RESULT_OK {
t.Fatalf("CreateSharedBuffer failed:%v", r)
}
if !h0.IsValid() {
t.Fatalf("CreateSharedBuffer returned an invalid handle h0:%v", h0)
}
if r, buf = h0.MapBuffer(0, 100, system.MOJO_MAP_BUFFER_FLAG_NONE); r != system.MOJO_RESULT_OK {
t.Fatalf("MapBuffer failed to map buffer with h0:%v", r)
}
if len(buf) != 100 || cap(buf) != 100 {
t.Fatalf("Buffer length(%d) and capacity(%d) should be %d", len(buf), cap(buf), 100)
}
buf[50] = 'x'
if r, h1 = h0.DuplicateBufferHandle(nil); r != system.MOJO_RESULT_OK {
t.Fatalf("DuplicateBufferHandle of h0 failed:%v", r)
}
if !h1.IsValid() {
t.Fatalf("DuplicateBufferHandle returned an invalid handle h1:%v", h1)
}
if r = h0.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on h0 failed:%v", r)
}
buf[51] = 'y'
if r = h1.UnmapBuffer(buf); r != system.MOJO_RESULT_OK {
t.Fatalf("UnmapBuffer failed:%v", r)
}
if r, buf = h1.MapBuffer(50, 50, system.MOJO_MAP_BUFFER_FLAG_NONE); r != system.MOJO_RESULT_OK {
t.Fatalf("MapBuffer failed to map buffer with h1:%v", r)
}
if len(buf) != 50 || cap(buf) != 50 {
t.Fatalf("Buffer length(%d) and capacity(%d) should be %d", len(buf), cap(buf), 50)
}
if buf[0] != 'x' || buf[1] != 'y' {
t.Fatalf("Failed to validate shared buffer. expected:x,y got:%s,%s", buf[0], buf[1])
}
if r = h1.UnmapBuffer(buf); r != system.MOJO_RESULT_OK {
t.Fatalf("UnmapBuffer failed:%v", r)
}
if r = h1.Close(); r != system.MOJO_RESULT_OK {
t.Fatalf("Close on h1 failed:%v", r)
}
}