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