blob: ee65530f82fa53ec44266b4f6ae2900b6f49174e [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <stdlib.h>
17#include <memory>
18#include <string>
19#include <thread>
20
21#include <glog/logging.h>
22#include <gmock/gmock.h>
23#include <gtest/gtest.h>
24
25#include "common/libs/fs/shared_fd.h"
26#include "host/commands/ivserver/hald_client.h"
27#include "host/commands/ivserver/vsocsharedmem_mock.h"
28
29using ::testing::_;
30using ::testing::DoAll;
31using ::testing::Return;
32using ::testing::ReturnRef;
33using ::testing::SetArgPointee;
34
35namespace ivserver {
36namespace test {
37
38class HaldClientTest : public ::testing::Test {
39 public:
40 void SetUp() override {
41 std::string socket_location;
42 ASSERT_TRUE(GetTempLocation(&socket_location))
43 << "Could not create temp file";
44 LOG(INFO) << "Temp file location: " << socket_location;
45
46 hald_server_socket_ = cvd::SharedFD::SocketLocalServer(
47 socket_location.c_str(), false, SOCK_STREAM, 0666);
48 test_socket_ = cvd::SharedFD::SocketLocalClient(socket_location.c_str(),
49 false, SOCK_STREAM);
50 hald_socket_ =
51 cvd::SharedFD::Accept(*hald_server_socket_, nullptr, nullptr);
52
53 EXPECT_TRUE(hald_server_socket_->IsOpen());
54 EXPECT_TRUE(test_socket_->IsOpen());
55 EXPECT_TRUE(hald_socket_->IsOpen());
56 }
57
58 bool GetTempLocation(std::string* target) {
59 char temp_location[] = "/tmp/hald-client-test-XXXXXX";
60 mktemp(temp_location);
61 *target = temp_location;
62 if (target->size()) {
63 cleanup_files_.emplace_back(*target);
64 return true;
65 }
66 return false;
67 }
68
69 void TearDown() override {
70 hald_socket_->Close();
71 test_socket_->Close();
72 hald_server_socket_->Close();
73
74 for (const std::string& file : cleanup_files_) {
75 unlink(file.c_str());
76 }
77 }
78
79 protected:
80 ::testing::NiceMock<VSoCSharedMemoryMock> vsoc_;
81
82 cvd::SharedFD hald_server_socket_;
83 cvd::SharedFD hald_socket_;
84 cvd::SharedFD test_socket_;
85
86 private:
87 std::vector<std::string> cleanup_files_;
88};
89
90TEST_F(HaldClientTest, HandshakeTerminatedByHald) {
91 std::thread thread(
92 [this]() {
93 auto client(HaldClient::New(vsoc_, hald_socket_));
94 EXPECT_FALSE(client)
95 << "Handshake should not complete when client terminates early.";
96 });
97
98 test_socket_->Close();
99 thread.join();
100}
101
102TEST_F(HaldClientTest, HandshakeTerminatedByInvalidRegionSize) {
103 uint16_t sizes[] = {0, VSOC_DEVICE_NAME_SZ + 1, 0xffff};
104
105 for (uint16_t size : sizes) {
106 std::thread thread([this, size]() {
107 auto client(HaldClient::New(vsoc_, hald_socket_));
108 EXPECT_FALSE(client) << "Handle should not be created when size is "
109 << size;
110 });
111
112 int32_t proto_version;
113 EXPECT_EQ(sizeof(proto_version),
114 static_cast<size_t>(test_socket_->Recv(
115 &proto_version, sizeof(proto_version), MSG_NOSIGNAL)));
116
117 test_socket_->Send(&size, sizeof(size), MSG_NOSIGNAL);
118 thread.join();
119 }
120}
121
122TEST_F(HaldClientTest, FullSaneHandshake) {
123 std::string temp;
124 ASSERT_TRUE(GetTempLocation(&temp));
125 cvd::SharedFD host_fd(
126 cvd::SharedFD::Open(temp.c_str(), O_CREAT | O_RDWR, 0666));
127 EXPECT_TRUE(host_fd->IsOpen());
128
129 ASSERT_TRUE(GetTempLocation(&temp));
130 cvd::SharedFD guest_fd(
131 cvd::SharedFD::Open(temp.c_str(), O_CREAT | O_RDWR, 0666));
132 EXPECT_TRUE(guest_fd->IsOpen());
133
134 ASSERT_TRUE(GetTempLocation(&temp));
135 cvd::SharedFD shmem_fd(
136 cvd::SharedFD::Open(temp.c_str(), O_CREAT | O_RDWR, 0666));
137 EXPECT_TRUE(shmem_fd->IsOpen());
138
139 const std::string test_location("testing");
140 EXPECT_CALL(vsoc_, GetEventFdPairForRegion(test_location, _, _))
141 .WillOnce(DoAll(SetArgPointee<1>(host_fd), SetArgPointee<2>(guest_fd),
142 Return(true)));
143 EXPECT_CALL(vsoc_, SharedMemFD()).WillOnce(ReturnRef(shmem_fd));
144
145 std::thread thread([this]() {
146 auto client(HaldClient::New(vsoc_, hald_socket_));
147 EXPECT_TRUE(client);
148 });
149
150 int32_t proto_version;
151 EXPECT_EQ(sizeof(proto_version),
152 static_cast<size_t>(test_socket_->Recv(
153 &proto_version, sizeof(proto_version), MSG_NOSIGNAL)));
154
155 uint16_t size = test_location.size();
156 EXPECT_EQ(sizeof(size), static_cast<size_t>(test_socket_->Send(
157 &size, sizeof(size), MSG_NOSIGNAL)));
158 EXPECT_EQ(size, static_cast<size_t>(test_socket_->Send(test_location.data(),
159 size, MSG_NOSIGNAL)));
160
161 // TODO(ender): delete this once no longer necessary. Currently, absence of
162 // payload makes RecvMsgAndFDs hang forever.
163 uint64_t control_data;
164 struct iovec vec {
165 &control_data, sizeof(control_data)
166 };
167 cvd::InbandMessageHeader hdr{nullptr, 0, &vec, 1, 0};
168 cvd::SharedFD fds[3];
169
170 EXPECT_GT(test_socket_->RecvMsgAndFDs<3>(hdr, MSG_NOSIGNAL, &fds), 0);
171 EXPECT_TRUE(fds[0]->IsOpen());
172 EXPECT_TRUE(fds[1]->IsOpen());
173 EXPECT_TRUE(fds[2]->IsOpen());
174
175 thread.join();
176}
177
178} // namespace test
179} // namespace ivserver