10955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell/* 20955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * Copyright (C) 2015 The Android Open Source Project 30955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * 40955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * Licensed under the Apache License, Version 2.0 (the "License"); 50955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * you may not use this file except in compliance with the License. 60955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * You may obtain a copy of the License at 70955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * 80955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * http://www.apache.org/licenses/LICENSE-2.0 90955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * 100955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * Unless required by applicable law or agreed to in writing, software 110955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * distributed under the License is distributed on an "AS IS" BASIS, 120955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * See the License for the specific language governing permissions and 140955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell * limitations under the License. 150955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell */ 160955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 170955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include "shell_service.h" 180955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 190955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include <gtest/gtest.h> 200955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 210955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include <signal.h> 220955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 230955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include <string> 240955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include <vector> 250955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 264f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include <android-base/strings.h> 270955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 280955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include "adb.h" 290955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include "adb_io.h" 300955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell#include "sysdeps.h" 310955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 320955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellclass ShellServiceTest : public ::testing::Test { 330955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell public: 340955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell static void SetUpTestCase() { 350955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // This is normally done in main.cpp. 360955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN); 370955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 380955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 390955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 400955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell static void TearDownTestCase() { 410955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell signal(SIGPIPE, saved_sigpipe_handler_); 420955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 430955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 440955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // Helpers to start and cleanup a subprocess. Cleanup normally does not 450955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // need to be called manually unless multiple subprocesses are run from 460955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // a single test. 470955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell void StartTestSubprocess(const char* command, SubprocessType type, 480955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessProtocol protocol); 490955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell void CleanupTestSubprocess(); 500955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 510955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell virtual void TearDown() override { 520955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell void CleanupTestSubprocess(); 530955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 540955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 550955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell static sighandler_t saved_sigpipe_handler_; 560955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 570955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell int subprocess_fd_ = -1; 580955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell}; 590955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 600955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellsighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr; 610955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 620955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellvoid ShellServiceTest::StartTestSubprocess( 630955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell const char* command, SubprocessType type, SubprocessProtocol protocol) { 6418ddf5c6a233bd56d20548fd834c0ecbf8216410Elliott Hughes subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol); 650955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_TRUE(subprocess_fd_ >= 0); 660955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 670955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 680955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellvoid ShellServiceTest::CleanupTestSubprocess() { 690955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell if (subprocess_fd_ >= 0) { 700955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell adb_close(subprocess_fd_); 710955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell subprocess_fd_ = -1; 720955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 730955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 740955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 750955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellnamespace { 760955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 770955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Reads raw data from |fd| until it closes or errors. 780955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellstd::string ReadRaw(int fd) { 790955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell char buffer[1024]; 800955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell char *cur_ptr = buffer, *end_ptr = buffer + sizeof(buffer); 810955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 820955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell while (1) { 830955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell int bytes = adb_read(fd, cur_ptr, end_ptr - cur_ptr); 840955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell if (bytes <= 0) { 850955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell return std::string(buffer, cur_ptr); 860955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 870955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell cur_ptr += bytes; 880955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 890955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 900955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 910955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Reads shell protocol data from |fd| until it closes or errors. Fills 920955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// |stdout| and |stderr| with their respective data, and returns the exit code 930955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// read from the protocol or -1 if an exit code packet was not received. 940955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellint ReadShellProtocol(int fd, std::string* stdout, std::string* stderr) { 950955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell int exit_code = -1; 960955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell stdout->clear(); 970955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell stderr->clear(); 980955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 990955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ShellProtocol* protocol = new ShellProtocol(fd); 1000955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell while (protocol->Read()) { 1010955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell switch (protocol->id()) { 1020955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell case ShellProtocol::kIdStdout: 1030955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell stdout->append(protocol->data(), protocol->data_length()); 1040955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell break; 1050955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell case ShellProtocol::kIdStderr: 1060955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell stderr->append(protocol->data(), protocol->data_length()); 1070955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell break; 1080955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell case ShellProtocol::kIdExit: 1090955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(-1, exit_code) << "Multiple exit packets received"; 1100955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(1u, protocol->data_length()); 1110955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell exit_code = protocol->data()[0]; 1120955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell break; 1130955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell default: 1140955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ADD_FAILURE() << "Unidentified packet ID: " << protocol->id(); 1150955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 1160955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 1170955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell delete protocol; 1180955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1190955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell return exit_code; 1200955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 1210955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1220955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Checks if each line in |lines| exists in the same order in |output|. Blank 1230955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// lines in |output| are ignored for simplicity. 1240955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursellbool ExpectLinesEqual(const std::string& output, 1250955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell const std::vector<std::string>& lines) { 1260955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell auto output_lines = android::base::Split(output, "\r\n"); 1270955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell size_t i = 0; 1280955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1290955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell for (const std::string& line : lines) { 1300955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // Skip empty lines in output. 1310955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell while (i < output_lines.size() && output_lines[i].empty()) { 1320955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ++i; 1330955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 1340955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell if (i >= output_lines.size()) { 1350955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ADD_FAILURE() << "Ran out of output lines"; 1360955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell return false; 1370955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 1380955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(line, output_lines[i]); 1390955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ++i; 1400955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 1410955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1420955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell while (i < output_lines.size() && output_lines[i].empty()) { 1430955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ++i; 1440955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 1450955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(i, output_lines.size()) << "Found unmatched output lines"; 1460955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell return true; 1470955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 1480955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1490955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} // namespace 1500955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1510955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests a raw subprocess with no protocol. 1520955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, RawNoProtocolSubprocess) { 1530955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // [ -t 0 ] checks if stdin is connected to a terminal. 1540955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 1550955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "echo foo; echo bar >&2; [ -t 0 ]; echo $?", 1560955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessType::kRaw, SubprocessProtocol::kNone)); 1570955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 15857dd5ae1e3004daec664263e24dc4dcf4475bb02David Pursell // [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without 15957dd5ae1e3004daec664263e24dc4dcf4475bb02David Pursell // the shell protocol we should always force a PTY to ensure proper cleanup. 16057dd5ae1e3004daec664263e24dc4dcf4475bb02David Pursell ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"}); 1610955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 1620955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1630955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests a PTY subprocess with no protocol. 1640955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, PtyNoProtocolSubprocess) { 1650955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // [ -t 0 ] checks if stdin is connected to a terminal. 1660955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 1670955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "echo foo; echo bar >&2; [ -t 0 ]; echo $?", 1680955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessType::kPty, SubprocessProtocol::kNone)); 1690955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1700955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // [ -t 0 ] == 0 means we have a terminal (PTY). 1710955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"}); 1720955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 1730955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1740955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests a raw subprocess with the shell protocol. 1750955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, RawShellProtocolSubprocess) { 1760955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 1770955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "echo foo; echo bar >&2; echo baz; exit 24", 1780955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessType::kRaw, SubprocessProtocol::kShell)); 1790955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1800955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell std::string stdout, stderr; 1810955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(24, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); 1820955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stdout, {"foo", "baz"}); 1830955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stderr, {"bar"}); 1840955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 1850955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1860955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests a PTY subprocess with the shell protocol. 1870955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, PtyShellProtocolSubprocess) { 1880955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 1890955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "echo foo; echo bar >&2; echo baz; exit 50", 1900955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessType::kPty, SubprocessProtocol::kShell)); 1910955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 1920955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // PTY always combines stdout and stderr but the shell protocol should 1930955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // still give us an exit code. 1940955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell std::string stdout, stderr; 1950955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(50, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); 1960955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stdout, {"foo", "bar", "baz"}); 1970955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stderr, {}); 1980955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 1990955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2000955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests an interactive PTY session. 2010955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, InteractivePtySubprocess) { 2020955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 2030955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "", SubprocessType::kPty, SubprocessProtocol::kShell)); 2040955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2050955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // Use variable substitution so echoed input is different from output. 2060955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell const char* commands[] = {"TEST_STR=abc123", 2070955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "echo --${TEST_STR}--", 2080955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "exit"}; 2090955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2100955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ShellProtocol* protocol = new ShellProtocol(subprocess_fd_); 2110955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell for (std::string command : commands) { 2120955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // Interactive shell requires a newline to complete each command. 2130955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell command.push_back('\n'); 2140955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell memcpy(protocol->data(), command.data(), command.length()); 2150955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, command.length())); 2160955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 2170955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell delete protocol; 2180955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2190955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell std::string stdout, stderr; 2200955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); 2210955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // An unpredictable command prompt makes parsing exact output difficult but 2220955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell // it should at least contain echoed input and the expected output. 2230955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell for (const char* command : commands) { 2240955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_FALSE(stdout.find(command) == std::string::npos); 2250955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell } 2260955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_FALSE(stdout.find("--abc123--") == std::string::npos); 2270955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 2280955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2291ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell// Tests closing raw subprocess stdin. 2301ed57f0dc333c0bc0800e222c569cca8a71deb89David PursellTEST_F(ShellServiceTest, CloseClientStdin) { 2311ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 2321ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell "cat; echo TEST_DONE", 2331ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell SubprocessType::kRaw, SubprocessProtocol::kShell)); 2341ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell 2351ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell std::string input = "foo\nbar"; 2361ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell ShellProtocol* protocol = new ShellProtocol(subprocess_fd_); 2371ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell memcpy(protocol->data(), input.data(), input.length()); 2381ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length())); 2391ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0)); 2401ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell delete protocol; 2411ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell 2421ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell std::string stdout, stderr; 2431ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); 2441ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"}); 2451ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell ExpectLinesEqual(stderr, {}); 2461ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell} 2471ed57f0dc333c0bc0800e222c569cca8a71deb89David Pursell 2480955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests that nothing breaks when the stdin/stdout pipe closes. 2490955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, CloseStdinStdoutSubprocess) { 2500955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 2510955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "exec 0<&-; exec 1>&-; echo bar >&2", 2520955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessType::kRaw, SubprocessProtocol::kShell)); 2530955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2540955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell std::string stdout, stderr; 2550955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); 2560955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stdout, {}); 2570955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stderr, {"bar"}); 2580955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 2590955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2600955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell// Tests that nothing breaks when the stderr pipe closes. 2610955c66b226db7a7f34613f834f7b0a145fd407dDavid PursellTEST_F(ShellServiceTest, CloseStderrSubprocess) { 2620955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ASSERT_NO_FATAL_FAILURE(StartTestSubprocess( 2630955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell "exec 2>&-; echo foo", 2640955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell SubprocessType::kRaw, SubprocessProtocol::kShell)); 2650955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell 2660955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell std::string stdout, stderr; 2670955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); 2680955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stdout, {"foo"}); 2690955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell ExpectLinesEqual(stderr, {}); 2700955c66b226db7a7f34613f834f7b0a145fd407dDavid Pursell} 271