1 /*
2  * Copyright 2016 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 "ShellDriverTest.h"
18 
19 #include <errno.h>
20 #include <gtest/gtest.h>
21 #include <limits.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <unistd.h>
29 
30 #include <iostream>
31 #include <sstream>
32 
33 #include <VtsDriverCommUtil.h>
34 #include "test/vts/proto/VtsDriverControlMessage.pb.h"
35 
36 #include "ShellDriver.h"
37 
38 using namespace std;
39 
40 namespace android {
41 namespace vts {
42 
43 static int kMaxRetry = 3;
44 
45 /*
46  * send a command to the driver on specified UNIX domain socket and print out
47  * the outputs from driver.
48  */
vts_shell_driver_test_client_start(const string & command,const string & socket_address)49 static string vts_shell_driver_test_client_start(const string& command,
50                                                  const string& socket_address) {
51   struct sockaddr_un address;
52   int socket_fd;
53 
54   socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
55   if (socket_fd < 0) {
56     fprintf(stderr, "socket() failed\n");
57     return "";
58   }
59 
60   VtsDriverCommUtil driverUtil(socket_fd);
61 
62   memset(&address, 0, sizeof(struct sockaddr_un));
63 
64   address.sun_family = AF_UNIX;
65   strncpy(address.sun_path, socket_address.c_str(),
66           sizeof(address.sun_path) - 1);
67 
68   int conn_success;
69   int retry_count = 0;
70 
71   conn_success = connect(socket_fd, (struct sockaddr*)&address,
72                          sizeof(struct sockaddr_un));
73   for (retry_count = 0; retry_count < kMaxRetry && conn_success != 0;
74        retry_count++) {  // retry if server not ready
75     printf("Client: connection failed, retrying...\n");
76     retry_count++;
77     if (usleep(50 * pow(retry_count, 3)) != 0) {
78       fprintf(stderr, "shell driver unit test: sleep intrupted.");
79     }
80 
81     conn_success = connect(socket_fd, (struct sockaddr*)&address,
82                            sizeof(struct sockaddr_un));
83   }
84 
85   if (conn_success != 0) {
86     fprintf(stderr, "connect() failed\n");
87     return "";
88   }
89 
90   VtsDriverControlCommandMessage cmd_msg;
91 
92   cmd_msg.add_shell_command(command);
93   cmd_msg.set_command_type(EXECUTE_COMMAND);
94 
95   if (!driverUtil.VtsSocketSendMessage(cmd_msg)) {
96     return NULL;
97   }
98 
99   // read driver output
100   VtsDriverControlResponseMessage out_msg;
101 
102   if (!driverUtil.VtsSocketRecvMessage(
103           static_cast<google::protobuf::Message*>(&out_msg))) {
104     return "";
105   }
106 
107   // TODO(yuexima) use vector for output messages
108   stringstream ss;
109   for (int i = 0; i < out_msg.stdout_size(); i++) {
110     string out_str = out_msg.stdout(i);
111     cout << "[Shell driver] output for command " << i << ": " << out_str
112          << endl;
113     ss << out_str;
114   }
115   close(socket_fd);
116 
117   cout << "[Client] receiving output: " << ss.str() << endl;
118   return ss.str();
119 }
120 
121 /*
122  * Prototype unit test helper. It first forks a vts_shell_driver process
123  * and then call a client function to execute a command.
124  */
test_shell_command_output(const string & command,const string & socket_address)125 static string test_shell_command_output(const string& command,
126                                         const string& socket_address) {
127   pid_t p_driver;
128   string res_client;
129 
130   VtsShellDriver shellDriver(socket_address.c_str());
131 
132   p_driver = fork();
133   if (p_driver == 0) {  // child
134     int res_driver = shellDriver.StartListen();
135 
136     if (res_driver != 0) {
137       fprintf(stderr, "Driver reported error. The error code is: %d.\n",
138               res_driver);
139       exit(res_driver);
140     }
141 
142     exit(0);
143   } else if (p_driver > 0) {  // parent
144     res_client = vts_shell_driver_test_client_start(command, socket_address);
145     if (res_client.empty()) {
146       fprintf(stderr, "Client reported error.\n");
147       exit(1);
148     }
149     cout << "Client receiving: " << res_client << endl;
150   } else {
151     fprintf(stderr,
152             "shell_driver_test.cpp: create child process failed for driver.");
153     exit(-1);
154   }
155 
156   // send kill signal to insure the process would not block
157   kill(p_driver, SIGKILL);
158 
159   return res_client;
160 }
161 
162 /*
163  * This test tests whether the output of "uname" is "Linux\n"
164  */
TEST(vts_shell_driver_start,vts_shell_driver_unit_test_uname)165 TEST(vts_shell_driver_start, vts_shell_driver_unit_test_uname) {
166   string expected = "Linux\n";
167   string output =
168       test_shell_command_output("uname", "/data/local/tmp/test1_1.tmp");
169   ASSERT_EQ(output.compare(expected), 0);
170 }
171 
172 /*
173  * This test tests whether the output of "which ls" is "/system/bin/ls\n"
174  */
TEST(vts_shell_driver_start,vts_shell_driver_unit_test_which_ls)175 TEST(vts_shell_driver_start, vts_shell_driver_unit_test_which_ls) {
176   string expected = "/system/bin/ls\n";
177   string output =
178       test_shell_command_output("which ls", "/data/local/tmp/test1_2.tmp");
179   ASSERT_EQ(output.compare(expected), 0);
180 }
181 
182 }  // namespace vts
183 }  // namespace android
184