1 /*
2 * Copyright (C) 2023 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
17 #include "test_utils.h"
18
19 #include <android-base/strings.h>
20 #include <android-base/test_utils.h>
21
22 #include <cutils/sockets.h>
23 #include <gtest/gtest.h>
24
25 #include "shell_protocol.h"
26 #include "sysdeps.h"
27
28 namespace test_utils {
29
30 // Reads raw data from |fd| until it closes or errors.
ReadRaw(android::base::borrowed_fd fd)31 std::string ReadRaw(android::base::borrowed_fd fd) {
32 char buffer[1024];
33 char *cur_ptr = buffer, *end_ptr = buffer + sizeof(buffer);
34
35 while (1) {
36 int bytes = adb_read(fd, cur_ptr, end_ptr - cur_ptr);
37 if (bytes <= 0) {
38 return std::string(buffer, cur_ptr);
39 }
40 cur_ptr += bytes;
41 }
42 }
43
44 // Reads shell protocol data from |fd| until it closes or errors. Fills
45 // |stdout| and |stderr| with their respective data, and returns the exit code
46 // read from the protocol or -1 if an exit code packet was not received.
ReadShellProtocol(android::base::borrowed_fd fd,std::string * std_out,std::string * std_err)47 int ReadShellProtocol(android::base::borrowed_fd fd, std::string* std_out, std::string* std_err) {
48 int exit_code = -1;
49 std_out->clear();
50 std_err->clear();
51
52 auto protocol = std::make_unique<ShellProtocol>(fd.get());
53 while (protocol->Read()) {
54 switch (protocol->id()) {
55 case ShellProtocol::kIdStdout:
56 std_out->append(protocol->data(), protocol->data_length());
57 break;
58 case ShellProtocol::kIdStderr:
59 std_err->append(protocol->data(), protocol->data_length());
60 break;
61 case ShellProtocol::kIdExit:
62 EXPECT_EQ(-1, exit_code) << "Multiple exit packets received";
63 EXPECT_EQ(1u, protocol->data_length());
64 exit_code = protocol->data()[0];
65 break;
66 default:
67 ADD_FAILURE() << "Unidentified packet ID: " << protocol->id();
68 }
69 }
70
71 return exit_code;
72 }
73
74 // Checks if each line in |lines| exists in the same order in |output|. Blank
75 // lines in |output| are ignored for simplicity.
ExpectLinesEqual(const std::string & output,const std::vector<std::string> & lines)76 bool ExpectLinesEqual(const std::string& output, const std::vector<std::string>& lines) {
77 auto output_lines = android::base::Split(output, "\r\n");
78 size_t i = 0;
79
80 for (const std::string& line : lines) {
81 // Skip empty lines in output.
82 while (i < output_lines.size() && output_lines[i].empty()) {
83 ++i;
84 }
85 if (i >= output_lines.size()) {
86 ADD_FAILURE() << "Ran out of output lines";
87 return false;
88 }
89 EXPECT_EQ(output_lines[i], line);
90 ++i;
91 }
92
93 while (i < output_lines.size() && output_lines[i].empty()) {
94 ++i;
95 }
96 EXPECT_EQ(i, output_lines.size()) << "Found unmatched output lines";
97 return true;
98 }
99
100 // Relies on the device to allocate an available port, and
101 // returns it to the caller. Also returns the associated fd.
102 // Existing client (LocalSocketTest) of this interface is
103 // implemented only on Linux, hence using cutils.
GetUnassignedPort(android::base::unique_fd & fd)104 int GetUnassignedPort(android::base::unique_fd& fd) {
105 fd.reset(socket_inaddr_any_server(0, SOCK_STREAM));
106 EXPECT_NE(static_cast<cutils_socket_t>(fd.get()), INVALID_SOCKET);
107
108 const int port = socket_get_local_port(fd.get());
109 EXPECT_GT(port, 0);
110
111 return port;
112 }
113
114 } // namespace test_utils
115