Commit 3ee40a33 authored by Chris Jones's avatar Chris Jones
Browse files

Bug 564086, part r: Test IPDL |bridge|

parent 1f57d8d4
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ EXPORT_LIBRARY = 1

IPDLTESTS = \
  TestBlockChild \
  TestBridgeMain \
  TestCrashCleanup \
  TestDataStructures \
  TestDesc \
@@ -89,7 +90,9 @@ ifeq ($(OS_ARCH),Linux)
IPDLTESTS += TestSysVShmem
endif

EXTRA_PROTOCOLS =
EXTRA_PROTOCOLS = \
  TestBridgeSub \
  $(NULL)

IPDLTESTSRCS = $(addsuffix .cpp,$(IPDLTESTS))
IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
+24 −0
Original line number Diff line number Diff line
include protocol PTestBridgeSub;

namespace mozilla {
namespace _ipdltest {


protocol PTestBridgeMain {
    child spawns PTestBridgeSub;

child:
    Start();

parent:
    __delete__();

state START:
    send Start goto DEAD;
state DEAD:
    recv __delete__;
};


} // namespace mozilla
} // namespace _ipdltest
+33 −0
Original line number Diff line number Diff line
include protocol PTestBridgeMain;
include protocol PTestBridgeSub;

namespace mozilla {
namespace _ipdltest {

// (Bridge protocols can have different semantics than the endpoints
// they bridge)
rpc protocol PTestBridgeMainSub {
    bridges PTestBridgeMain, PTestBridgeSub;

child:
    Hi();
    rpc HiRpc();

parent:
    Hello();
    sync HelloSync();
    rpc HelloRpc();
    __delete__();

state START:       recv Hello goto HI;
state HI:          send Hi goto HELLO_SYNC;
state HELLO_SYNC:  recv HelloSync goto HELLO_RPC;
state HELLO_RPC:   answer HelloRpc goto HI_RPC;
state HI_RPC:      call HiRpc goto DEAD;
state DEAD:
    recv __delete__;
};


} // namespace mozilla
} // namespace _ipdltest
+24 −0
Original line number Diff line number Diff line

namespace mozilla {
namespace _ipdltest {


protocol PTestBridgeSub {
child:
    Ping();

parent:
    BridgeEm();
    __delete__();

state START:
    send Ping goto BRIDGEEM;
state BRIDGEEM:
    recv BridgeEm goto DEAD;
state DEAD:
    recv __delete__;
};


} // namespace mozilla
} // namespace _ipdltest
+252 −0
Original line number Diff line number Diff line
#include "TestBridgeMain.h"

#include "IPDLUnitTests.h"      // fail etc.
#include "IPDLUnitTestSubprocess.h"

using namespace std;

template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestBridgeMainSubChild>
{
    static void RetainCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { }
    static void ReleaseCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { }
};

namespace mozilla {
namespace _ipdltest {


//-----------------------------------------------------------------------------
// main process
void
TestBridgeMainParent::Main()
{
    if (!SendStart())
        fail("sending Start");
}

PTestBridgeMainSubParent*
TestBridgeMainParent::AllocPTestBridgeMainSub(Transport* transport,
                                              ProcessId otherProcess)
{
    ProcessHandle h;
    if (!base::OpenProcessHandle(otherProcess, &h)) {
        return nsnull;
    }

    nsAutoPtr<TestBridgeMainSubParent> a(new TestBridgeMainSubParent(transport));
    if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Parent)) {
        return nsnull;
    }
    return a.forget();
}

void
TestBridgeMainParent::ActorDestroy(ActorDestroyReason why)
{
    if (NormalShutdown != why)
        fail("unexpected destruction!");  
    passed("ok");
    QuitParent();
}

bool
TestBridgeMainSubParent::RecvHello()
{
    return SendHi();
}

bool
TestBridgeMainSubParent::RecvHelloSync()
{
    return true;
}

bool
TestBridgeMainSubParent::AnswerHelloRpc()
{
    return CallHiRpc();
}

void
TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
{
    if (NormalShutdown != why)
        fail("unexpected destruction!");

    // ActorDestroy() is just a callback from IPDL-generated code,
    // which needs the top-level actor (this) to stay alive a little
    // longer so other things can be cleaned up.
    MessageLoop::current()->PostTask(
        FROM_HERE,
        new DeleteTask<TestBridgeMainSubParent>(this));
    XRE_GetIOMessageLoop()->PostTask(
        FROM_HERE,
        new DeleteTask<Transport>(mTransport));
}

//-----------------------------------------------------------------------------
// sub process --- child of main
TestBridgeMainChild* gBridgeMainChild;

TestBridgeMainChild::TestBridgeMainChild()
    : mSubprocess(nsnull)
{
    gBridgeMainChild = this;
}

bool
TestBridgeMainChild::RecvStart()
{
    vector<string> subsubArgs;
    subsubArgs.push_back("TestBridgeSub");

    mSubprocess = new IPDLUnitTestSubprocess();
    if (!mSubprocess->SyncLaunch(subsubArgs))
        fail("problem launching subprocess");

    IPC::Channel* transport = mSubprocess->GetChannel();
    if (!transport)
        fail("no transport");

    TestBridgeSubParent* bsp = new TestBridgeSubParent();
    bsp->Open(transport, mSubprocess->GetChildProcessHandle());

    bsp->Main();
    return true;
}

void
TestBridgeMainChild::ActorDestroy(ActorDestroyReason why)
{
    if (NormalShutdown != why)
        fail("unexpected destruction!");  
    // NB: this is kosher because QuitChild() joins with the IO thread
    XRE_GetIOMessageLoop()->PostTask(
        FROM_HERE,
        new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess));
    QuitChild();
}

void
TestBridgeSubParent::Main()
{
    if (!SendPing())
        fail("sending Ping");
}

bool
TestBridgeSubParent::RecvBridgeEm()
{
    if (!PTestBridgeMainSub::Bridge(gBridgeMainChild, this))
        fail("bridging Main and Sub");
    return true;
}

void
TestBridgeSubParent::ActorDestroy(ActorDestroyReason why)
{
    if (NormalShutdown != why)
        fail("unexpected destruction!");
    gBridgeMainChild->Close();

    // ActorDestroy() is just a callback from IPDL-generated code,
    // which needs the top-level actor (this) to stay alive a little
    // longer so other things can be cleaned up.
    MessageLoop::current()->PostTask(
        FROM_HERE,
        new DeleteTask<TestBridgeSubParent>(this));
}

//-----------------------------------------------------------------------------
// subsub process --- child of sub

static TestBridgeSubChild* gBridgeSubChild;

TestBridgeSubChild::TestBridgeSubChild()
{
    gBridgeSubChild = this;   
}

bool
TestBridgeSubChild::RecvPing()
{
    if (!SendBridgeEm())
        fail("sending BridgeEm");
    return true;
}

PTestBridgeMainSubChild*
TestBridgeSubChild::AllocPTestBridgeMainSub(Transport* transport,
                                            ProcessId otherProcess)
{
    ProcessHandle h;
    if (!base::OpenProcessHandle(otherProcess, &h)) {
        return nsnull;
    }

    nsAutoPtr<TestBridgeMainSubChild> a(new TestBridgeMainSubChild(transport));
    if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Child)) {
        return nsnull;
    }

    if (!a->SendHello())
        fail("sending Hello");

    return a.forget();
}

void
TestBridgeSubChild::ActorDestroy(ActorDestroyReason why)
{
    if (NormalShutdown != why)
        fail("unexpected destruction!");
    QuitChild();
}

bool
TestBridgeMainSubChild::RecvHi()
{
    if (!SendHelloSync())
        fail("sending HelloSync");
    if (!CallHelloRpc())
        fail("calling HelloRpc");
    if (!mGotHi)
        fail("didn't answer HiRpc");

    // Need to close the channel without message-processing frames on
    // the C++ stack
    MessageLoop::current()->PostTask(
        FROM_HERE,
        NewRunnableMethod(this, &TestBridgeMainSubChild::Close));
    return true;
}

bool
TestBridgeMainSubChild::AnswerHiRpc()
{
    mGotHi = true;              // d00d
    return true;
}

void
TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
{
    if (NormalShutdown != why)
        fail("unexpected destruction!");  

    gBridgeSubChild->Close();

    // ActorDestroy() is just a callback from IPDL-generated code,
    // which needs the top-level actor (this) to stay alive a little
    // longer so other things can be cleaned up.
    MessageLoop::current()->PostTask(
        FROM_HERE,
        new DeleteTask<TestBridgeMainSubChild>(this));
    XRE_GetIOMessageLoop()->PostTask(
        FROM_HERE,
        new DeleteTask<Transport>(mTransport));
}

} // namespace mozilla
} // namespace _ipdltest
Loading