diff options
author | torkve <torkve@yandex-team.ru> | 2022-02-10 16:48:23 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:48:23 +0300 |
commit | d2e3ef74aed5c066cc49df962b30ceb4318778ac (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /util/system | |
parent | f9cfbeee51d5849127bb58793a2edcdfd7bb91bb (diff) | |
download | ydb-d2e3ef74aed5c066cc49df962b30ceb4318778ac.tar.gz |
Restoring authorship annotation for <torkve@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'util/system')
-rw-r--r-- | util/system/shellcommand.cpp | 202 | ||||
-rw-r--r-- | util/system/shellcommand.h | 316 | ||||
-rw-r--r-- | util/system/shellcommand_ut.cpp | 116 |
3 files changed, 317 insertions, 317 deletions
diff --git a/util/system/shellcommand.cpp b/util/system/shellcommand.cpp index 9b30cfcc1b..b1989b5c8c 100644 --- a/util/system/shellcommand.cpp +++ b/util/system/shellcommand.cpp @@ -1,4 +1,4 @@ -#include "shellcommand.h" +#include "shellcommand.h" #include "user.h" #include "nice.h" #include "sigset.h" @@ -10,14 +10,14 @@ #include <util/generic/vector.h> #include <util/generic/yexception.h> #include <util/memory/tempbuf.h> -#include <util/network/socket.h> +#include <util/network/socket.h> #include <util/stream/pipe.h> -#include <util/stream/str.h> +#include <util/stream/str.h> #include <util/string/cast.h> #include <util/system/info.h> -#include <errno.h> - +#include <errno.h> + #if defined(_unix_) #include <unistd.h> #include <fcntl.h> @@ -177,7 +177,7 @@ public: TRealPipeHandle(fds[1]).Swap(writer); } -private: +private: REALPIPEHANDLE Fd_; }; @@ -203,7 +203,7 @@ private: TString CollectedError; TString InternalError; TThread* WatchThread; - TMutex TerminateMutex; + TMutex TerminateMutex; TFileHandle InputHandle; TFileHandle OutputHandle; TFileHandle ErrorHandle; @@ -227,8 +227,8 @@ private: THashMap<TString, TString> Environment; int Nice = 0; std::function<void()> FuncAfterFork = {}; - - struct TProcessInfo { + + struct TProcessInfo { TImpl* Parent; TRealPipeHandle InputFd; TRealPipeHandle OutputFd; @@ -239,9 +239,9 @@ private: , OutputFd(outputFd) , ErrorFd(errorFd) { - } - }; - + } + }; + struct TPipes { TRealPipeHandle OutputPipeFd[2]; TRealPipeHandle ErrorPipeFd[2]; @@ -279,7 +279,7 @@ private: void StartProcess(TPipes& pipes); #endif -public: +public: inline TImpl(const TStringBuf cmd, const TList<TString>& args, const TShellCommandOptions& options, const TString& workdir) : Pid(0) , Command(ToString(cmd)) @@ -307,61 +307,61 @@ public: , Environment(options.Environment) , Nice(options.Nice) , FuncAfterFork(options.FuncAfterFork) - { + { if (InputStream) { // TODO change usages to call SetInputStream instead of directly assigning to InputStream InputMode = TShellCommandOptions::HANDLE_STREAM; } - } - - inline ~TImpl() { - if (WatchThread) { + } + + inline ~TImpl() { + if (WatchThread) { with_lock (TerminateMutex) { - TerminateFlag = true; - } + TerminateFlag = true; + } - delete WatchThread; - } + delete WatchThread; + } #if defined(_win_) if (Pid) { CloseHandle(Pid); } #endif - } - + } + inline void AppendArgument(const TStringBuf argument) { if (AtomicGet(ExecutionStatus) == SHELL_RUNNING) { - ythrow yexception() << "You cannot change command parameters while process is running"; - } + ythrow yexception() << "You cannot change command parameters while process is running"; + } Arguments.push_back(ToString(argument)); - } - + } + inline const TString& GetOutput() const { if (AtomicGet(ExecutionStatus) == SHELL_RUNNING) { - ythrow yexception() << "You cannot retrieve output while process is running."; - } - return CollectedOutput; - } - + ythrow yexception() << "You cannot retrieve output while process is running."; + } + return CollectedOutput; + } + inline const TString& GetError() const { if (AtomicGet(ExecutionStatus) == SHELL_RUNNING) { - ythrow yexception() << "You cannot retrieve output while process is running."; - } - return CollectedError; - } - + ythrow yexception() << "You cannot retrieve output while process is running."; + } + return CollectedError; + } + inline const TString& GetInternalError() const { if (AtomicGet(ExecutionStatus) != SHELL_INTERNAL_ERROR) { - ythrow yexception() << "Internal error hasn't occured so can't be retrieved."; - } - return InternalError; - } - - inline ECommandStatus GetStatus() const { + ythrow yexception() << "Internal error hasn't occured so can't be retrieved."; + } + return InternalError; + } + + inline ECommandStatus GetStatus() const { return static_cast<ECommandStatus>(AtomicGet(ExecutionStatus)); - } - + } + inline TMaybe<int> GetExitCode() const { return ExitCode; } @@ -388,7 +388,7 @@ public: // start child process void Run(); - + inline void Terminate() { if (!!Pid && (AtomicGet(ExecutionStatus) == SHELL_RUNNING)) { bool ok = @@ -408,24 +408,24 @@ public: } } - inline void Wait() { + inline void Wait() { if (WatchThread) { - WatchThread->Join(); + WatchThread->Join(); } - } - + } + inline void CloseInput() { AtomicSet(ShouldCloseInput, true); } inline static bool TerminateIsRequired(void* processInfo) { TProcessInfo* pi = reinterpret_cast<TProcessInfo*>(processInfo); - if (!pi->Parent->TerminateFlag) { - return false; - } - pi->InputFd.Close(); - pi->ErrorFd.Close(); - pi->OutputFd.Close(); + if (!pi->Parent->TerminateFlag) { + return false; + } + pi->InputFd.Close(); + pi->ErrorFd.Close(); + pi->OutputFd.Close(); if (pi->Parent->CloseStreams) { if (pi->Parent->ErrorStream) { @@ -436,13 +436,13 @@ public: } } - delete pi; - return true; - } - + delete pi; + return true; + } + // interchange io while process is alive inline static void Communicate(TProcessInfo* pi); - + inline static void* WatchProcess(void* data) { TProcessInfo* pi = reinterpret_cast<TProcessInfo*>(data); Communicate(pi); @@ -511,7 +511,7 @@ public: TString GetQuotedCommand() const; }; - + #if defined(_win_) void TShellCommand::TImpl::StartProcess(TShellCommand::TImpl::TPipes& pipes) { // Setup STARTUPINFO to redirect handles. @@ -931,9 +931,9 @@ void TShellCommand::TImpl::Communicate(TProcessInfo* pi) { { with_lock (pi->Parent->TerminateMutex) { if (TerminateIsRequired(pi)) { - return; + return; } - } + } waitPidResult = #if defined(_unix_) @@ -1039,20 +1039,20 @@ void TShellCommand::TImpl::Communicate(TProcessInfo* pi) { input = nullptr; } continue; - } + } bufPos = inputBuffer.Data(); - } + } bytes = pi->InputFd.Write(bufPos, bytesToWrite); if (bytes > 0) { bytesToWrite -= bytes; bufPos += bytes; - } else { + } else { input = nullptr; - } + } DBG(Cerr << "transferred " << bytes << " bytes of input" << Endl); - } + } #endif } DBG(Cerr << "process finished" << Endl); @@ -1075,19 +1075,19 @@ void TShellCommand::TImpl::Communicate(TProcessInfo* pi) { DWORD exitCode = STILL_ACTIVE; if (!GetExitCodeProcess(pi->Parent->Pid, &exitCode)) { ythrow yexception() << "GetExitCodeProcess: " << LastSystemErrorText(); - } + } if (exitCode == 0) cleanExit = true; processExitCode = static_cast<int>(exitCode); DBG(Cerr << "exit code: " << exitCode << Endl); - } + } #endif pi->Parent->ExitCode = processExitCode; if (cleanExit) { AtomicSet(pi->Parent->ExecutionStatus, SHELL_FINISHED); } else { AtomicSet(pi->Parent->ExecutionStatus, SHELL_ERROR); - } + } #if defined(_win_) for (auto& threadHolder : streamThreads) @@ -1115,12 +1115,12 @@ void TShellCommand::TImpl::Communicate(TProcessInfo* pi) { pi->InputFd.Close(); } Cdbg << "shell command internal error: " << pi->Parent->InternalError << Endl; - } + } // Now we can safely delete process info struct and other data pi->Parent->TerminateFlag = true; TerminateIsRequired(pi); } - + TShellCommand::TShellCommand(const TStringBuf cmd, const TList<TString>& args, const TShellCommandOptions& options, const TString& workdir) : Impl(new TImpl(cmd, args, options, workdir)) @@ -1129,32 +1129,32 @@ TShellCommand::TShellCommand(const TStringBuf cmd, const TList<TString>& args, c TShellCommand::TShellCommand(const TStringBuf cmd, const TShellCommandOptions& options, const TString& workdir) : Impl(new TImpl(cmd, TList<TString>(), options, workdir)) -{ -} - +{ +} + TShellCommand::~TShellCommand() = default; - + TShellCommand& TShellCommand::operator<<(const TStringBuf argument) { Impl->AppendArgument(argument); - return *this; -} - + return *this; +} + const TString& TShellCommand::GetOutput() const { - return Impl->GetOutput(); -} - + return Impl->GetOutput(); +} + const TString& TShellCommand::GetError() const { - return Impl->GetError(); -} - + return Impl->GetError(); +} + const TString& TShellCommand::GetInternalError() const { - return Impl->GetInternalError(); -} - + return Impl->GetInternalError(); +} + TShellCommand::ECommandStatus TShellCommand::GetStatus() const { - return Impl->GetStatus(); -} - + return Impl->GetStatus(); +} + TMaybe<int> TShellCommand::GetExitCode() const { return Impl->GetExitCode(); } @@ -1176,19 +1176,19 @@ TFileHandle& TShellCommand::GetErrorHandle() { } TShellCommand& TShellCommand::Run() { - Impl->Run(); - return *this; -} - + Impl->Run(); + return *this; +} + TShellCommand& TShellCommand::Terminate() { Impl->Terminate(); return *this; } TShellCommand& TShellCommand::Wait() { - Impl->Wait(); - return *this; -} + Impl->Wait(); + return *this; +} TShellCommand& TShellCommand::CloseInput() { Impl->CloseInput(); diff --git a/util/system/shellcommand.h b/util/system/shellcommand.h index d787bf6384..8730627fe5 100644 --- a/util/system/shellcommand.h +++ b/util/system/shellcommand.h @@ -1,21 +1,21 @@ -#pragma once - -#include <util/generic/noncopyable.h> +#pragma once + +#include <util/generic/noncopyable.h> #include <util/generic/string.h> -#include <util/generic/list.h> +#include <util/generic/list.h> #include <util/generic/hash.h> -#include <util/generic/strbuf.h> +#include <util/generic/strbuf.h> #include <util/generic/maybe.h> -#include <util/stream/input.h> -#include <util/stream/output.h> +#include <util/stream/input.h> +#include <util/stream/output.h> #include "file.h" #include "getpid.h" #include "thread.h" #include "mutex.h" -#include <sys/types.h> - +#include <sys/types.h> + class TShellCommandOptions { -public: +public: struct TUserOptions { TString Name; #if defined(_win_) @@ -57,15 +57,15 @@ public: , Nice(0) , FuncAfterFork(std::function<void()>()) { - } - + } + inline TShellCommandOptions& SetNice(int value) noexcept { Nice = value; return *this; } - /** + /** * @brief clear signal mask from parent process. If true, child process * clears the signal mask inherited from the parent process; otherwise * child process retains the signal mask of the parent process. @@ -94,21 +94,21 @@ public: } /** - * @brief set asynchronous mode. If true, task will be run - * in separate thread, and control will be returned immediately - * - * @param async true if asynchonous mode is needed + * @brief set asynchronous mode. If true, task will be run + * in separate thread, and control will be returned immediately + * + * @param async true if asynchonous mode is needed * @note in default async mode launcher will need 100% cpu for rapid process termination - * @return self - */ + * @return self + */ inline TShellCommandOptions& SetAsync(bool async) { - AsyncMode = async; + AsyncMode = async; if (AsyncMode) PollDelayMs = 0; - return *this; - } - - /** + return *this; + } + + /** * @brief specify delay for process controlling loop * @param ms number of milliseconds to poll for * @note for synchronous process default of 1s should generally fit @@ -122,52 +122,52 @@ public: } /** - * @brief set the stream, which is input fetched from - * - * @param stream Pointer to stream. - * If stream is NULL or not set, input channel will be closed. - * - * @return self - */ + * @brief set the stream, which is input fetched from + * + * @param stream Pointer to stream. + * If stream is NULL or not set, input channel will be closed. + * + * @return self + */ inline TShellCommandOptions& SetInputStream(IInputStream* stream) { - InputStream = stream; + InputStream = stream; if (InputStream == nullptr) { InputMode = HANDLE_INHERIT; } else { InputMode = HANDLE_STREAM; } - return *this; - } - - /** - * @brief set the stream, collecting the command output - * - * @param stream Pointer to stream. - * If stream is NULL or not set, output will be collected to the - * internal variable - * - * @return self - */ + return *this; + } + + /** + * @brief set the stream, collecting the command output + * + * @param stream Pointer to stream. + * If stream is NULL or not set, output will be collected to the + * internal variable + * + * @return self + */ inline TShellCommandOptions& SetOutputStream(IOutputStream* stream) { - OutputStream = stream; - return *this; - } - - /** - * @brief set the stream, collecting the command error output - * - * @param stream Pointer to stream. - * If stream is NULL or not set, errors will be collected to the - * internal variable - * - * @return self - */ + OutputStream = stream; + return *this; + } + + /** + * @brief set the stream, collecting the command error output + * + * @param stream Pointer to stream. + * If stream is NULL or not set, errors will be collected to the + * internal variable + * + * @return self + */ inline TShellCommandOptions& SetErrorStream(IOutputStream* stream) { - ErrorStream = stream; - return *this; - } - - /** + ErrorStream = stream; + return *this; + } + + /** * @brief set if Finish() should be called on user-supplied streams * if process is run in async mode Finish will be called in process' thread * @param val if Finish() should be called @@ -205,25 +205,25 @@ public: } /** - * @brief set if the arguments should be wrapped in quotes. - * Please, note that this option makes no difference between - * real arguments and shell syntax, so if you execute something - * like \b TShellCommand("sleep") << "3" << "&&" << "ls", your - * command will look like: - * sleep "3" "&&" "ls" - * which will never end successfully. - * By default, this option is turned on. - * + * @brief set if the arguments should be wrapped in quotes. + * Please, note that this option makes no difference between + * real arguments and shell syntax, so if you execute something + * like \b TShellCommand("sleep") << "3" << "&&" << "ls", your + * command will look like: + * sleep "3" "&&" "ls" + * which will never end successfully. + * By default, this option is turned on. + * * @note arguments will only be quoted if shell is used - * @param quote if the arguments should be quoted - * - * @return self - */ + * @param quote if the arguments should be quoted + * + * @return self + */ inline TShellCommandOptions& SetQuoteArguments(bool quote) { - QuoteArguments = quote; - return *this; - } - + QuoteArguments = quote; + return *this; + } + /** * @brief set to run command in new session * @note set this option to off to deliver parent's signals to command as well @@ -323,82 +323,82 @@ public: static const size_t DefaultSyncPollDelay = 1000; // ms std::function<void()> FuncAfterFork = {}; -}; - -/** - * @brief Execute command in shell and provide its results - * @attention Not thread-safe - */ +}; + +/** + * @brief Execute command in shell and provide its results + * @attention Not thread-safe + */ class TShellCommand: public TNonCopyable { -private: - TShellCommand(); - -public: - enum ECommandStatus { - SHELL_NONE, - SHELL_RUNNING, - SHELL_FINISHED, - SHELL_INTERNAL_ERROR, - SHELL_ERROR - }; - -public: - /** - * @brief create the command with initial arguments list - * - * @param cmd binary name - * @param args arguments list - * @param options execution options +private: + TShellCommand(); + +public: + enum ECommandStatus { + SHELL_NONE, + SHELL_RUNNING, + SHELL_FINISHED, + SHELL_INTERNAL_ERROR, + SHELL_ERROR + }; + +public: + /** + * @brief create the command with initial arguments list + * + * @param cmd binary name + * @param args arguments list + * @param options execution options * @todo store entire options structure - */ + */ TShellCommand(const TStringBuf cmd, const TList<TString>& args, const TShellCommandOptions& options = TShellCommandOptions(), const TString& workdir = TString()); TShellCommand(const TStringBuf cmd, const TShellCommandOptions& options = TShellCommandOptions(), const TString& workdir = TString()); ~TShellCommand(); -public: - /** - * @brief append argument to the args list - * - * @param argument string argument - * - * @return self - */ +public: + /** + * @brief append argument to the args list + * + * @param argument string argument + * + * @return self + */ TShellCommand& operator<<(const TStringBuf argument); - - /** - * @brief return the collected output from the command. - * If the output stream is set, empty string will be returned - * - * @return collected output - */ + + /** + * @brief return the collected output from the command. + * If the output stream is set, empty string will be returned + * + * @return collected output + */ const TString& GetOutput() const; - - /** - * @brief return the collected error output from the command. - * If the error stream is set, empty string will be returned - * - * @return collected error output - */ + + /** + * @brief return the collected error output from the command. + * If the error stream is set, empty string will be returned + * + * @return collected error output + */ const TString& GetError() const; - - /** - * @brief return the internal error occured while watching - * the command execution. Should be called if execution - * status is SHELL_INTERNAL_ERROR - * - * @return error text - */ + + /** + * @brief return the internal error occured while watching + * the command execution. Should be called if execution + * status is SHELL_INTERNAL_ERROR + * + * @return error text + */ const TString& GetInternalError() const; - - /** - * @brief get current status of command execution - * - * @return current status - */ - ECommandStatus GetStatus() const; - - /** + + /** + * @brief get current status of command execution + * + * @return current status + */ + ECommandStatus GetStatus() const; + + /** * @brief return exit code of finished process * The value is unspecified in case of internal errors or if the process is running * @@ -436,13 +436,13 @@ public: TFileHandle& GetErrorHandle(); /** - * @brief run the execution - * - * @return self - */ + * @brief run the execution + * + * @return self + */ TShellCommand& Run(); - - /** + + /** * @brief terminate the execution * @note if DetachSession is set, it terminates all procs in command's new process group * @@ -451,10 +451,10 @@ public: TShellCommand& Terminate(); /** - * @brief wait until the execution is finished - * - * @return self - */ + * @brief wait until the execution is finished + * + * @return self + */ TShellCommand& Wait(); /** @@ -469,11 +469,11 @@ public: **/ TString GetQuotedCommand() const; -private: - class TImpl; +private: + class TImpl; using TImplRef = TSimpleIntrusivePtr<TImpl>; - TImplRef Impl; -}; + TImplRef Impl; +}; /// Appends to dst: quoted arg void ShellQuoteArg(TString& dst, TStringBuf arg); diff --git a/util/system/shellcommand_ut.cpp b/util/system/shellcommand_ut.cpp index c5e1ca8d76..9d849279d2 100644 --- a/util/system/shellcommand_ut.cpp +++ b/util/system/shellcommand_ut.cpp @@ -12,11 +12,11 @@ #include <util/folder/dirut.h> #include <util/random/random.h> #include <util/stream/file.h> -#include <util/stream/str.h> -#include <util/stream/mem.h> -#include <util/string/strip.h> +#include <util/stream/str.h> +#include <util/stream/mem.h> +#include <util/string/strip.h> #include <util/folder/tempdir.h> - + #if defined(_win_) #define NL "\r\n" const char catCommand[] = "sort"; // not really cat but ok @@ -119,7 +119,7 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { const char dir[] = "ls"; #endif - TShellCommandOptions options; + TShellCommandOptions options; options.SetQuoteArguments(false); { @@ -145,7 +145,7 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { } Y_UNIT_TEST(TestAsyncRun) { TShellCommandOptions options; - options.SetAsync(true); + options.SetAsync(true); #if defined(_win_) // fails with weird error "Input redirection is not supported" // TShellCommand cmd("sleep", options); @@ -155,43 +155,43 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { TShellCommand cmd("sleep", options); cmd << "2"; #endif - UNIT_ASSERT(TShellCommand::SHELL_NONE == cmd.GetStatus()); - cmd.Run(); - sleep(1); - UNIT_ASSERT(TShellCommand::SHELL_RUNNING == cmd.GetStatus()); - cmd.Wait(); + UNIT_ASSERT(TShellCommand::SHELL_NONE == cmd.GetStatus()); + cmd.Run(); + sleep(1); + UNIT_ASSERT(TShellCommand::SHELL_RUNNING == cmd.GetStatus()); + cmd.Wait(); UNIT_ASSERT(TShellCommand::SHELL_RUNNING != cmd.GetStatus()); UNIT_ASSERT_VALUES_EQUAL(cmd.GetError(), ""); #if !defined(_win_) - UNIT_ASSERT(TShellCommand::SHELL_FINISHED == cmd.GetStatus()); + UNIT_ASSERT(TShellCommand::SHELL_FINISHED == cmd.GetStatus()); UNIT_ASSERT_VALUES_EQUAL(cmd.GetOutput().size(), 0u); UNIT_ASSERT(cmd.GetExitCode().Defined() && 0 == cmd.GetExitCode()); #endif - } + } Y_UNIT_TEST(TestQuotes) { - TShellCommandOptions options; + TShellCommandOptions options; TString input = TString("a\"a a"); TString output; - TStringOutput outputStream(output); - options.SetOutputStream(&outputStream); + TStringOutput outputStream(output); + options.SetOutputStream(&outputStream); TShellCommand cmd("echo", options); - cmd << input; - cmd.Run().Wait(); - output = StripString(output); + cmd << input; + cmd.Run().Wait(); + output = StripString(output); #if defined(_win_) UNIT_ASSERT_VALUES_EQUAL("\"a\\\"a a\"", output); #else - UNIT_ASSERT_VALUES_EQUAL(input, output); + UNIT_ASSERT_VALUES_EQUAL(input, output); #endif UNIT_ASSERT_VALUES_EQUAL(cmd.GetError().size(), 0u); - } + } Y_UNIT_TEST(TestRunNonexistent) { - TShellCommand cmd("iwerognweiofnewio"); // some nonexistent command name - cmd.Run().Wait(); - UNIT_ASSERT(TShellCommand::SHELL_ERROR == cmd.GetStatus()); + TShellCommand cmd("iwerognweiofnewio"); // some nonexistent command name + cmd.Run().Wait(); + UNIT_ASSERT(TShellCommand::SHELL_ERROR == cmd.GetStatus()); UNIT_ASSERT_VALUES_UNEQUAL(cmd.GetError().size(), 0u); UNIT_ASSERT(cmd.GetExitCode().Defined() && 0 != cmd.GetExitCode()); - } + } Y_UNIT_TEST(TestExitCode) { TShellCommand cmd("grep qwerty qwerty"); // some nonexistent file name cmd.Run().Wait(); @@ -201,28 +201,28 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { } // 'type con' and 'copy con con' want real console, not stdin, use sort Y_UNIT_TEST(TestInput) { - TShellCommandOptions options; + TShellCommandOptions options; TString input = (TString("a") * 2000).append(NL) * textSize; - TStringInput inputStream(input); - options.SetInputStream(&inputStream); + TStringInput inputStream(input); + options.SetInputStream(&inputStream); TShellCommand cmd(catCommand, options); - cmd.Run().Wait(); - UNIT_ASSERT_VALUES_EQUAL(input, cmd.GetOutput()); + cmd.Run().Wait(); + UNIT_ASSERT_VALUES_EQUAL(input, cmd.GetOutput()); UNIT_ASSERT_VALUES_EQUAL(cmd.GetError().size(), 0u); - } + } Y_UNIT_TEST(TestOutput) { - TShellCommandOptions options; + TShellCommandOptions options; TString input = (TString("a") * 2000).append(NL) * textSize; - TStringInput inputStream(input); - options.SetInputStream(&inputStream); + TStringInput inputStream(input); + options.SetInputStream(&inputStream); TString output; - TStringOutput outputStream(output); - options.SetOutputStream(&outputStream); + TStringOutput outputStream(output); + options.SetOutputStream(&outputStream); TShellCommand cmd(catCommand, options); - cmd.Run().Wait(); - UNIT_ASSERT_VALUES_EQUAL(input, output); + cmd.Run().Wait(); + UNIT_ASSERT_VALUES_EQUAL(input, output); UNIT_ASSERT_VALUES_EQUAL(cmd.GetError().size(), 0u); - } + } Y_UNIT_TEST(TestIO) { // descriptive test: use all options TShellCommandOptions options; @@ -299,24 +299,24 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { Y_UNIT_TEST(TestInterrupt) { TString tmpfile = TString("shellcommand_ut.interrupt.") + ToString(RandomNumber<ui32>()); - TShellCommandOptions options; - options.SetAsync(true); - options.SetQuoteArguments(false); - { - TShellCommand cmd("/bin/sleep", options); + TShellCommandOptions options; + options.SetAsync(true); + options.SetQuoteArguments(false); + { + TShellCommand cmd("/bin/sleep", options); cmd << " 1300 & wait; /usr/bin/touch " << tmpfile; - cmd.Run(); - sleep(1); - UNIT_ASSERT(TShellCommand::SHELL_RUNNING == cmd.GetStatus()); + cmd.Run(); + sleep(1); + UNIT_ASSERT(TShellCommand::SHELL_RUNNING == cmd.GetStatus()); // Async mode requires Terminate() + Wait() to send kill to child proc! cmd.Terminate(); cmd.Wait(); UNIT_ASSERT(TShellCommand::SHELL_ERROR == cmd.GetStatus()); UNIT_ASSERT(cmd.GetExitCode().Defined() && -15 == cmd.GetExitCode()); - } - sleep(1); + } + sleep(1); UNIT_ASSERT(!NFs::Exists(tmpfile)); - } + } // this ut is unix-only (win has no signal mask) Y_UNIT_TEST(TestSignalMask) { // block SIGTERM @@ -382,16 +382,16 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { #endif Y_UNIT_TEST(TestInternalError) { TString input = (TString("a") * 2000).append("\n"); - TStringInput inputStream(input); + TStringInput inputStream(input); TMemoryOutput outputStream(nullptr, 0); - TShellCommandOptions options; - options.SetInputStream(&inputStream); - options.SetOutputStream(&outputStream); + TShellCommandOptions options; + options.SetInputStream(&inputStream); + options.SetOutputStream(&outputStream); TShellCommand cmd(catCommand, options); - cmd.Run().Wait(); - UNIT_ASSERT(TShellCommand::SHELL_INTERNAL_ERROR == cmd.GetStatus()); + cmd.Run().Wait(); + UNIT_ASSERT(TShellCommand::SHELL_INTERNAL_ERROR == cmd.GetStatus()); UNIT_ASSERT_VALUES_UNEQUAL(cmd.GetInternalError().size(), 0u); - } + } Y_UNIT_TEST(TestHugeOutput) { TShellCommandOptions options; TGuardedStringStream stream; @@ -490,4 +490,4 @@ Y_UNIT_TEST_SUITE(TShellCommandTest) { UNIT_ASSERT_VALUES_EQUAL(firstLine, text); } -} +} |