Chromium Code Reviews| Index: runtime/vm/port_test.cc |
| =================================================================== |
| --- runtime/vm/port_test.cc (revision 448) |
| +++ runtime/vm/port_test.cc (working copy) |
| @@ -3,52 +3,146 @@ |
| // BSD-style license that can be found in the LICENSE file. |
| #include "vm/assert.h" |
| +#include "vm/message_queue.h" |
| +#include "vm/os.h" |
| #include "vm/port.h" |
| #include "vm/unit_test.h" |
| namespace dart { |
| -TEST_CASE(Port) { |
| - const char* msg_data = "Hallo Velo!"; |
| - intptr_t port1 = PortMap::CreatePort(); |
| - intptr_t port2 = PortMap::CreatePort(); |
| - EXPECT(port1 != port2); |
| +// Intercept the post message callback and just store a copy of the message. |
| +static const int kMaxSavedMsg = 80; |
| +static char saved_msg[kMaxSavedMsg]; |
| +static bool MyPostMessageCallback(Dart_Isolate dest_isolate, |
| + Dart_Port dest_port, |
| + Dart_Port reply_port, |
| + Dart_Message dart_message) { |
| + const char* msg = reinterpret_cast<char*>(dart_message); |
| + OS::SNPrint(saved_msg, kMaxSavedMsg, "%s", msg); |
| + bool result = (strcmp(msg, "fail") != 0); |
| + free(dart_message); |
| + return result; |
| +} |
| - PortMessage* msg1 = new PortMessage(port1, 0, strdup(msg_data)); |
| - EXPECT_EQ(true, PortMap::PostMessage(msg1)); |
| - PortMessage* msg = PortMap::ReceiveMessage(10); |
| - EXPECT_EQ(port1, msg->dest_id()); |
| - EXPECT_EQ(msg1, msg); |
| - delete msg1; |
| - msg1 = new PortMessage(port2, 0, strdup(msg_data)); |
| - EXPECT_EQ(true, PortMap::PostMessage(msg1)); |
| - msg = PortMap::ReceiveMessage(10); |
| - EXPECT_EQ(port2, msg->dest_id()); |
| - EXPECT_EQ(msg1, msg); |
| - delete msg1; |
| +// Intercept the close port callback and remember which port was closed. |
| +static Dart_Port saved_port = 0; |
| +static void MyClosePortCallback(Dart_Isolate dart_isolate, |
| + Dart_Port port) { |
| + saved_port = port; |
| +} |
| + |
| +static void InitPortMapTest() { |
| + Dart_SetPostMessageCallback(&MyPostMessageCallback); |
| + Dart_SetClosePortCallback(&MyClosePortCallback); |
| + saved_port = 0; |
| + saved_msg[0] = '\0'; |
| +} |
| + |
| + |
| +TEST_CASE(PortMap_CreateAndCloseOnePort) { |
| + InitPortMapTest(); |
| + intptr_t port = PortMap::CreatePort(); |
| + EXPECT_NE(0, port); |
| + EXPECT(PortMap::IsActivePort(port)); |
| + |
| + PortMap::ClosePort(port); |
| + EXPECT(!PortMap::IsActivePort(port)); |
| + |
| + // Embedder was notified of port closure. |
| + EXPECT_EQ(port, saved_port); |
| +} |
| + |
| + |
| +TEST_CASE(PortMap_CreateAndCloseTwoPorts) { |
| + InitPortMapTest(); |
| + Dart_Port port1 = PortMap::CreatePort(); |
| + Dart_Port port2 = PortMap::CreatePort(); |
| + EXPECT(PortMap::IsActivePort(port1)); |
| + EXPECT(PortMap::IsActivePort(port2)); |
| + |
| + // Uniqueness |
|
siva
2011/10/14 21:01:52
'.'
turnidge
2011/10/14 23:08:02
Done.
|
| + EXPECT_NE(port1, port2); |
| + |
| PortMap::ClosePort(port1); |
| - EXPECT_EQ(false, PortMap::IsActivePort(port1)); |
| - msg1 = new PortMessage(port1, 0, strdup(msg_data)); |
| - EXPECT_EQ(false, PortMap::PostMessage(msg1)); |
| - delete msg1; |
| - EXPECT(PortMap::ReceiveMessage(10) == NULL); |
| + EXPECT(!PortMap::IsActivePort(port1)); |
| + EXPECT(PortMap::IsActivePort(port2)); |
| + EXPECT_EQ(port1, saved_port); |
| - EXPECT_EQ(true, PortMap::IsActivePort(port2)); |
| - msg1 = new PortMessage(port2, 0, strdup(msg_data)); |
| - EXPECT_EQ(true, PortMap::PostMessage(msg1)); |
| PortMap::ClosePort(port2); |
| - EXPECT(PortMap::ReceiveMessage(10) == NULL); |
| + EXPECT(!PortMap::IsActivePort(port1)); |
| + EXPECT(!PortMap::IsActivePort(port2)); |
| + EXPECT_EQ(port2, saved_port); |
| +} |
| + |
| +TEST_CASE(PortMap_ClosePorts) { |
| + InitPortMapTest(); |
| + Dart_Port port1 = PortMap::CreatePort(); |
| + Dart_Port port2 = PortMap::CreatePort(); |
| + EXPECT(PortMap::IsActivePort(port1)); |
| + EXPECT(PortMap::IsActivePort(port2)); |
| + |
| + // Close all ports at once |
|
siva
2011/10/14 21:01:52
once.
turnidge
2011/10/14 23:08:02
Done.
|
| + PortMap::ClosePorts(); |
| + EXPECT(!PortMap::IsActivePort(port1)); |
| + EXPECT(!PortMap::IsActivePort(port2)); |
| + |
| + // Embedder is notified to close all ports as well. |
| + EXPECT_EQ(kCloseAllPorts, saved_port); |
| +} |
| + |
| + |
| +TEST_CASE(PortMap_CreateManyPorts) { |
| + InitPortMapTest(); |
| for (int i = 0; i < 32; i++) { |
| - intptr_t port = PortMap::CreatePort(); |
| + Dart_Port port = PortMap::CreatePort(); |
| + EXPECT(PortMap::IsActivePort(port)); |
| PortMap::ClosePort(port); |
| + EXPECT(!PortMap::IsActivePort(port)); |
| } |
| } |
| +TEST_CASE(PortMap_PostMessage) { |
| + InitPortMapTest(); |
| + Dart_Port port = PortMap::CreatePort(); |
| + EXPECT(PortMap::PostMessage( |
| + port, 0, reinterpret_cast<Dart_Message>(strdup("msg")))); |
| + |
| + // Check that the post message callback was called. |
| + EXPECT_STREQ("msg", saved_msg); |
| + PortMap::ClosePorts(); |
| +} |
| + |
| + |
| +TEST_CASE(PortMap_PostMessageInvalidPort) { |
| + InitPortMapTest(); |
| + EXPECT(!PortMap::PostMessage( |
| + 0, 0, reinterpret_cast<Dart_Message>(strdup("msg")))); |
| + |
| + // Check that the post message callback was not called. |
| + EXPECT_STREQ("", saved_msg); |
|
siva
2011/10/14 21:01:52
The duped string is leaked in this case.
turnidge
2011/10/14 23:08:02
Ah. Good catch. I have added a call to free() in
|
| +} |
| + |
| + |
| +TEST_CASE(PortMap_PostMessageFailureInCallback) { |
| + InitPortMapTest(); |
| + Dart_Port port = PortMap::CreatePort(); |
| + |
| + // Our callback is rigged to return false when it sees the message |
| + // "fail". This return value is propagated out of PostMessage. |
| + EXPECT(!PortMap::PostMessage( |
| + port, 0, reinterpret_cast<Dart_Message>(strdup("fail")))); |
| + |
| + // Check that the post message callback was called. |
| + EXPECT_STREQ("fail", saved_msg); |
| + PortMap::ClosePorts(); |
| +} |
| + |
| + |
| // End-of-test marker. |
| static const intptr_t kEOT = 0xFFFF; |
| @@ -64,28 +158,44 @@ |
| } |
| +static PortMessage* NextMessage() { |
| + // Since only the isolate owning the port can close the port and remove it |
| + // from the port map and flush its messages, we can safely assume that the |
| + // all messages in the message queue are for active ports. |
|
siva
2011/10/14 21:01:52
"that the all messages ..." => "that all messages
turnidge
2011/10/14 23:08:02
I have just deleted this comment.
|
| + Isolate* isolate = Isolate::Current(); |
| + { |
| + PortMessage* result = isolate->message_queue()->Dequeue(); |
| + if (result == NULL) { |
| + isolate->message_queue()->Wait(0); |
| + result = isolate->message_queue()->Dequeue(); |
| + } |
| + return result; |
| + } |
| +} |
| + |
| + |
| void ThreadedPort_start(uword parameter) { |
| Dart::CreateIsolate(NULL, NULL); |
| intptr_t remote = parameter; |
| intptr_t local = PortMap::CreatePort(); |
| - PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(local))); |
| + PortMap::PostMessage(remote, 0, AllocIntData(local)); |
| intptr_t count = 0; |
| while (true) { |
| - PortMessage* msg = PortMap::ReceiveMessage(0); |
| - EXPECT_EQ(local, msg->dest_id()); |
| + PortMessage* msg = NextMessage(); |
| + EXPECT_EQ(local, msg->dest_port()); |
| EXPECT(msg != NULL); |
| if (GetIntData(msg->data()) == kEOT) { |
| break; |
| } |
| EXPECT(GetIntData(msg->data()) == count); |
| delete msg; |
| - PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(count * 2))); |
| + PortMap::PostMessage(remote, 0, AllocIntData(count * 2)); |
| count++; |
| } |
| - PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(kEOT))); |
| + PortMap::PostMessage(remote, 0, AllocIntData(kEOT)); |
| Dart::ShutdownIsolate(); |
| } |
| @@ -97,24 +207,24 @@ |
| Thread* thr = new Thread(ThreadedPort_start, local); |
| EXPECT(thr != NULL); |
| - PortMessage* msg = PortMap::ReceiveMessage(0); |
| - EXPECT_EQ(local, msg->dest_id()); |
| + PortMessage* msg = NextMessage(); |
| + EXPECT_EQ(local, msg->dest_port()); |
| EXPECT(msg != NULL); |
| intptr_t remote = GetIntData(msg->data()); // Get the remote port. |
| delete msg; |
| for (intptr_t i = 0; i < 10; i++) { |
| - PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(i))); |
| - PortMessage* msg = PortMap::ReceiveMessage(0); |
| - EXPECT_EQ(local, msg->dest_id()); |
| + PortMap::PostMessage(remote, 0, AllocIntData(i)); |
| + PortMessage* msg = NextMessage(); |
| + EXPECT_EQ(local, msg->dest_port()); |
| EXPECT(msg != NULL); |
| EXPECT_EQ(i * 2, GetIntData(msg->data())); |
| delete msg; |
| } |
| - PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(kEOT))); |
| - msg = PortMap::ReceiveMessage(0); |
| - EXPECT_EQ(local, msg->dest_id()); |
| + PortMap::PostMessage(remote, 0, AllocIntData(kEOT)); |
| + msg = NextMessage(); |
| + EXPECT_EQ(local, msg->dest_port()); |
| EXPECT(msg != NULL); |
| EXPECT_EQ(kEOT, GetIntData(msg->data())); |
| delete msg; |