| /* |
| * Copyright 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 "ShellDriverTest.h" |
| |
| #include <errno.h> |
| #include <gtest/gtest.h> |
| #include <limits.h> |
| #include <math.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| #include <unistd.h> |
| |
| #include <iostream> |
| #include <sstream> |
| |
| #include <VtsDriverCommUtil.h> |
| #include "test/vts/proto/VtsDriverControlMessage.pb.h" |
| |
| #include "ShellDriver.h" |
| |
| using namespace std; |
| |
| namespace android { |
| namespace vts { |
| |
| static int kMaxRetry = 3; |
| |
| /* |
| * send a command to the driver on specified UNIX domain socket and print out |
| * the outputs from driver. |
| */ |
| static string vts_shell_driver_test_client_start(const string& command, |
| const string& socket_address) { |
| struct sockaddr_un address; |
| int socket_fd; |
| |
| socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); |
| if (socket_fd < 0) { |
| fprintf(stderr, "socket() failed\n"); |
| return ""; |
| } |
| |
| VtsDriverCommUtil driverUtil(socket_fd); |
| |
| memset(&address, 0, sizeof(struct sockaddr_un)); |
| |
| address.sun_family = AF_UNIX; |
| strncpy(address.sun_path, socket_address.c_str(), |
| sizeof(address.sun_path) - 1); |
| |
| int conn_success; |
| int retry_count = 0; |
| |
| conn_success = connect(socket_fd, (struct sockaddr*)&address, |
| sizeof(struct sockaddr_un)); |
| for (retry_count = 0; retry_count < kMaxRetry && conn_success != 0; |
| retry_count++) { // retry if server not ready |
| printf("Client: connection failed, retrying...\n"); |
| retry_count++; |
| if (usleep(50 * pow(retry_count, 3)) != 0) { |
| fprintf(stderr, "shell driver unit test: sleep intrupted."); |
| } |
| |
| conn_success = connect(socket_fd, (struct sockaddr*)&address, |
| sizeof(struct sockaddr_un)); |
| } |
| |
| if (conn_success != 0) { |
| fprintf(stderr, "connect() failed\n"); |
| return ""; |
| } |
| |
| VtsDriverControlCommandMessage cmd_msg; |
| |
| cmd_msg.add_shell_command(command); |
| |
| if (!driverUtil.VtsSocketSendMessage(cmd_msg)) { |
| return NULL; |
| } |
| |
| // read driver output |
| VtsDriverControlResponseMessage out_msg; |
| |
| if (!driverUtil.VtsSocketRecvMessage( |
| static_cast<google::protobuf::Message*>(&out_msg))) { |
| return ""; |
| } |
| |
| // TODO(yuexima) use vector for output messages |
| stringstream ss; |
| for (int i = 0; i < out_msg.stdout_size(); i++) { |
| string out_str = out_msg.stdout(i); |
| cout << "[Shell driver] output for command " << i << ": " << out_str |
| << endl; |
| ss << out_str; |
| } |
| close(socket_fd); |
| |
| cout << "[Client] receiving output: " << ss.str() << endl; |
| return ss.str(); |
| } |
| |
| /* |
| * Prototype unit test helper. It first forks a vts_shell_driver process |
| * and then call a client function to execute a command. |
| */ |
| static string test_shell_command_output(const string& command, |
| const string& socket_address) { |
| int res = 0; |
| pid_t p_driver; |
| string res_client; |
| |
| VtsShellDriver shellDriver(socket_address.c_str()); |
| |
| p_driver = fork(); |
| if (p_driver == 0) { // child |
| int res_driver = shellDriver.StartListen(); |
| |
| if (res_driver != 0) { |
| fprintf(stderr, "Driver reported error. The error code is: %d.\n", |
| res_driver); |
| exit(res_driver); |
| } |
| |
| exit(0); |
| } else if (p_driver > 0) { // parent |
| res_client = vts_shell_driver_test_client_start(command, socket_address); |
| if (res_client.empty()) { |
| fprintf(stderr, "Client reported error.\n"); |
| exit(1); |
| } |
| cout << "Client receiving: " << res_client << endl; |
| } else { |
| fprintf(stderr, |
| "shell_driver_test.cpp: create child process failed for driver."); |
| exit(-1); |
| } |
| |
| // send kill signal to insure the process would not block |
| kill(p_driver, SIGKILL); |
| |
| return res_client; |
| } |
| |
| /* |
| * This test tests whether the output of "uname" is "Linux\n" |
| */ |
| TEST(vts_shell_driver_start, vts_shell_driver_unit_test_uname) { |
| string expected = "Linux\n"; |
| string output = test_shell_command_output("uname", "test1_1.tmp"); |
| ASSERT_EQ(output.compare(expected), 0); |
| } |
| |
| /* |
| * This test tests whether the output of "uname" is "Linux\n" |
| */ |
| TEST(vts_shell_driver_start, vts_shell_driver_unit_test_which_ls) { |
| string expected = "/system/bin/ls\n"; |
| string output = test_shell_command_output("which ls", "test1_2.tmp"); |
| ASSERT_EQ(output.compare(expected), 0); |
| } |
| |
| } // namespace vts |
| } // namespace android |