summaryrefslogtreecommitdiff
path: root/simpleperf/UnixSocket_test.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-10-24 16:53:32 -0700
committerYabin Cui <yabinc@google.com>2016-10-26 12:14:10 -0700
commit54500708aa5c6e776c59d3633b2aaed85455b20b (patch)
treeeef85fdaf1df19b417f3b37c539dad2b08a08954 /simpleperf/UnixSocket_test.cpp
parent58117c6714dcc329811c8ad97e54492422a7900c (diff)
downloadextras-54500708aa5c6e776c59d3633b2aaed85455b20b.tar.gz
simpleperf: Add UnixSocket.
It is used for communication between inplace-sampler-server and simpleperf. Bug: http://b/30974760 Test: run simpleperf_unit_test. Change-Id: I055763b73fd0aaa03fe008c185ca8b78ab5435f2
Diffstat (limited to 'simpleperf/UnixSocket_test.cpp')
-rw-r--r--simpleperf/UnixSocket_test.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/simpleperf/UnixSocket_test.cpp b/simpleperf/UnixSocket_test.cpp
new file mode 100644
index 00000000..da2bbb17
--- /dev/null
+++ b/simpleperf/UnixSocket_test.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UnixSocket.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <thread>
+
+TEST(UnixSocket, message_buffer_smoke) {
+ struct Message {
+ uint32_t len;
+ uint32_t type;
+ char data[10];
+ } send_msg;
+ constexpr size_t send_data_size = 1024;
+ std::vector<char> send_data(send_data_size);
+ std::vector<char> read_data;
+ for (size_t i = 0; i < send_data_size; ++i) {
+ send_data[i] = i & 0xff;
+ }
+ UnixSocketMessageBuffer buffer(100);
+ size_t per_msg_bytes = 0;
+ size_t send_bytes = 0;
+ while (true) {
+ // Send data as much as possible.
+ while (send_bytes < send_data_size) {
+ size_t n = std::min(per_msg_bytes, send_data_size - send_bytes);
+ per_msg_bytes = (per_msg_bytes + 1) % 10;
+ memcpy(send_msg.data, &send_data[send_bytes], n);
+ send_msg.len = sizeof(UnixSocketMessage) + n;
+ send_msg.type = n;
+ if (!buffer.StoreMessage(
+ *reinterpret_cast<UnixSocketMessage*>(&send_msg))) {
+ break;
+ }
+ send_bytes += n;
+ }
+ if (buffer.Empty()) {
+ break;
+ }
+ // Read one message.
+ std::vector<char> read_buf;
+ auto read_func = [&](size_t size) {
+ while (read_buf.size() < size) {
+ const char* p;
+ size_t n = buffer.PeekData(&p);
+ n = std::min(n, size - read_buf.size());
+ read_buf.insert(read_buf.end(), p, p + n);
+ buffer.CommitData(n);
+ }
+ };
+ read_func(sizeof(UnixSocketMessage));
+ Message* msg = reinterpret_cast<Message*>(read_buf.data());
+ size_t aligned_len = Align(msg->len, UnixSocketMessageAlignment);
+ read_func(aligned_len);
+ msg = reinterpret_cast<Message*>(read_buf.data());
+ ASSERT_EQ(msg->len, msg->type + sizeof(UnixSocketMessage));
+ read_data.insert(read_data.end(), msg->data, msg->data + msg->type);
+ }
+ ASSERT_EQ(send_data, read_data);
+}
+
+static void ClientToTestUndelayedMessage(const std::string& path,
+ bool& client_success) {
+ std::unique_ptr<UnixSocketConnection> client =
+ UnixSocketConnection::Connect(path, true);
+ ASSERT_TRUE(client != nullptr);
+ IOEventLoop loop;
+ // For each message received from the server, the client replies a msg
+ // with type + 1.
+ auto receive_message_callback = [&](const UnixSocketMessage& msg) {
+ if (msg.len != sizeof(UnixSocketMessage)) {
+ return false;
+ }
+ UnixSocketMessage reply_msg;
+ reply_msg.len = sizeof(UnixSocketMessage);
+ reply_msg.type = msg.type + 1;
+ return client->SendMessage(reply_msg, true);
+ };
+ auto close_connection_callback = [&]() { return loop.ExitLoop(); };
+ ASSERT_TRUE(client->PrepareForIO(loop, receive_message_callback,
+ close_connection_callback));
+ ASSERT_TRUE(loop.RunLoop());
+ client_success = true;
+}
+
+TEST(UnixSocket, undelayed_message) {
+ std::string path = "unix_socket_test_" + std::to_string(getpid());
+ std::unique_ptr<UnixSocketServer> server =
+ UnixSocketServer::Create(path, true);
+ ASSERT_TRUE(server != nullptr);
+ bool client_success = false;
+ std::thread thread(
+ [&]() { ClientToTestUndelayedMessage(path, client_success); });
+ std::unique_ptr<UnixSocketConnection> conn = server->AcceptConnection();
+ ASSERT_TRUE(conn != nullptr);
+ IOEventLoop loop;
+ uint32_t need_reply_type = 1;
+ // For each message received from the client, the server replies a msg
+ // with type + 1, and exits when type reaches 10.
+ auto receive_message_callback = [&](const UnixSocketMessage& msg) {
+ if (msg.len != sizeof(UnixSocketMessage) || msg.type != need_reply_type) {
+ return false;
+ }
+ if (need_reply_type >= 10) {
+ return conn->NoMoreMessage();
+ }
+ UnixSocketMessage new_msg;
+ new_msg.len = sizeof(UnixSocketMessage);
+ new_msg.type = msg.type + 1;
+ need_reply_type = msg.type + 2;
+ return conn->SendMessage(new_msg, true);
+ };
+ auto close_connection_callback = [&]() { return loop.ExitLoop(); };
+ ASSERT_TRUE(conn->PrepareForIO(loop, receive_message_callback,
+ close_connection_callback));
+ UnixSocketMessage msg;
+ msg.len = sizeof(UnixSocketMessage);
+ msg.type = 0;
+ ASSERT_TRUE(conn->SendMessage(msg, true));
+ ASSERT_TRUE(loop.RunLoop());
+ thread.join();
+ ASSERT_TRUE(client_success);
+}
+
+static void ClientToTestBufferedMessage(const std::string& path,
+ bool& client_success) {
+ std::unique_ptr<UnixSocketConnection> client =
+ UnixSocketConnection::Connect(path, true);
+ ASSERT_TRUE(client != nullptr);
+ IOEventLoop loop;
+ // The client exits once receiving a message from the server.
+ auto receive_message_callback = [&](const UnixSocketMessage& msg) {
+ if (msg.len != sizeof(UnixSocketMessage) || msg.type != 0) {
+ return false;
+ }
+ return client->NoMoreMessage();
+ };
+ auto close_connection_callback = [&]() { return loop.ExitLoop(); };
+ ASSERT_TRUE(client->PrepareForIO(loop, receive_message_callback,
+ close_connection_callback));
+ // The client sends buffered messages until the send buffer is full.
+ UnixSocketMessage msg;
+ msg.len = sizeof(UnixSocketMessage);
+ msg.type = 0;
+ while (true) {
+ msg.type++;
+ if (!client->SendMessage(msg, false)) {
+ break;
+ }
+ }
+ ASSERT_TRUE(loop.RunLoop());
+ client_success = true;
+}
+
+TEST(UnixSocket, buffered_message) {
+ std::string path = "unix_socket_test_" + std::to_string(getpid());
+ std::unique_ptr<UnixSocketServer> server =
+ UnixSocketServer::Create(path, true);
+ ASSERT_TRUE(server != nullptr);
+ bool client_success = false;
+ std::thread thread(
+ [&]() { ClientToTestBufferedMessage(path, client_success); });
+ std::unique_ptr<UnixSocketConnection> conn = server->AcceptConnection();
+ ASSERT_TRUE(conn != nullptr);
+ IOEventLoop loop;
+ uint32_t need_reply_type = 1;
+ auto receive_message_callback = [&](const UnixSocketMessage& msg) {
+ // The server checks if the type of received message is increased by one
+ // each time.
+ if (msg.len != sizeof(UnixSocketMessage) || msg.type != need_reply_type) {
+ return false;
+ }
+ if (need_reply_type == 1) {
+ // Notify the client to exit.
+ UnixSocketMessage new_msg;
+ new_msg.len = sizeof(UnixSocketMessage);
+ new_msg.type = 0;
+ if (!conn->SendMessage(new_msg, true)) {
+ return false;
+ }
+ }
+ need_reply_type++;
+ return true;
+ };
+ auto close_connection_callback = [&]() { return loop.ExitLoop(); };
+ ASSERT_TRUE(conn->PrepareForIO(loop, receive_message_callback,
+ close_connection_callback));
+ ASSERT_TRUE(loop.RunLoop());
+ thread.join();
+ ASSERT_TRUE(client_success);
+}