다음 코드에서 다음 코드를 실행하는 프로그램을 구현하려고합니다. 처리하고 반환 코드 인 stdout
및 stderr
를 반환합니다. 또한 자식 프로세스가 종료되는 시간 초과 개념이 있습니다. 이 클래스는 멀티 스레드 애플리케이션의 일부로 사용됩니다.
#ifndef PROCESS_H_ #define PROCESS_H_ //Header #include <chrono> #include <thread> #include <iostream> #include <boost/process.hpp> #include <boost/asio.hpp namespace bp = boost::process; class Proces { public: Process(const std::string& cmd, const int timeout); void run(); int getReturnStatus(); //Must be only called after run() exits std::string getStdOut(); //Must be only called after run() exits std::string getStdErr(); //Must be only called after run() exits bool wasKilled(); //Must be only called after run() exits private: void initLog(); void timeoutHandler(const boost::system::error_code& ec); void kill(); const std::string command; const int timeout; int returnStatus; std::string stdOut; std::string stdErr; bool killed; bool stopped; boost::process::group group; boost::asio::io_context ioc; boost::asio::deadline_timer deadline_timer; }; #endif //Source #include "Process.h" Process::Process(const std::string& cmd, const int timeout): command(cmd), timeout(timeout), returnStatus(0), stdOut(""), stdErr(""), killed(false), stopped(false), ioc(), deadline_timer(ioc) { } void Process::timeoutHandler(const boost::system::error_code& ec) { if (stopped || ec == boost::asio::error::operation_aborted) { return; } std::cout << "Time Up!"<< std::endl; kill(); deadline_timer.expires_at(boost::posix_time::pos_infin); } void Process::run() { std::future<std::string> dataOut; std::future<std::string> dataErr; std::cout << "Running command: " << command << std::endl; bp::child c(command, bp::std_in.close(), bp::std_out > dataOut, bp::std_err > dataErr, ioc, group, bp::on_exit([=](int e, const std::error_code& ec) { std::cout << "on_exit: " << ec.message() << " -> " << e << std::endl; deadline_timer.cancel(); returnStatus = e; })); deadline_timer.expires_from_now(boost::posix_time::seconds(timeout)); deadline_timer.async_wait(std::bind(&Process::timeoutHandler, this, std::placeholders::_1)); ioc.run(); c.wait(); stdOut = dataOut.get(); stdErr = dataErr.get(); } //Must be only called after run() exits int Process::getReturnStatus() { return returnStatus; } //Must be only called after run() exits std::string Process::getStdOut() { return stdOut; } //Must be only called after run() exits std::string Process::getStdErr() { return stdErr; } void Process::kill() { std::error_code ec; group.terminate(ec); if(ec) { std::cout << "Error occurred while trying to kill the process: " << ec.message(); throw std::runtime_error(ec.message()); } std::cout << "Killed the process and all its descendants" << std::endl; killed = true; stopped = true; } //Must be only called after run() exits bool Process::wasKilled() { return killed; }
다음은 테스트에 사용하는 코드입니다.
#define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE ProcessTest #include <boost/test/unit_test.hpp> #include "../src/Process.h" BOOST_AUTO_TEST_CASE( ProcessTest ) { const std::vector<std::string> commands = { "ls" , "pwd" , "uname -a" , "cat /proc/cpuinfo" , "wget https://dl.google.com/dl/earth/client/current/google-earth-pro-stable-current.x86_64.rpm"}; for(const auto& cmd: commands) { Process p(cmd, 3600); p.run(); BOOST_CHECK( p.getReturnStatus() == 0); // #1 continues on error } const std::vector<std::string> commandsThatShouldFail = { "ls doesnotexit" , "cat /proc/doesnotexist" , "wget https://dl.google.com/dl/earth/client/current/doesnotxist.rpm"}; for(const auto& cmd: commandsThatShouldFail) { Process p(cmd, 3600); p.run(); BOOST_CHECK( p.getReturnStatus() != 0); // #1 continues on error } }
귀중한 의견과 제안을 제공해주십시오.
댓글
- 코드 검토에 오신 것을 환영합니다! 프로그램을 구현하려고 '라고 말합니다. 지금까지 작동합니까? 코드에 대한 우려 사항이 있습니까? 코드가 의도 한대로 작동하는 한 ' ' t는 괜찮습니다.
- @Mast 코드는 내가 테스트 한 사례에서 작동합니다. 하지만 경쟁 조건과 기타 버그가 있는지 궁금합니다.
- 좋습니다! 이러한 테스트를 포함 할 수 있습니까?
답변
아직도 , 그래서 아마도 이것이 잘못되었습니다. 그러나 ios.run()
이후에 c.wait()
가 정말로 필요합니까?
문서 , io_context
이 완료 될 때까지 ios.run()
에서 제어가 차단되거나 deadline_timer
가 만료됩니다.
답변
누락 된 테스트
I 시간 초과해야하는 명령에 대한 테스트는 표시되지 않습니다. 1
div의 시간 초과로 실행하는 경우 명백한 예는 sleep 2
일 수 있습니다. >.보다 엄격한 테스트는 모든 신호 (무시할 수있는 신호)를 무시하는 명령입니다. SIGTERM
가 작동하지 않는 경우 SIGKILL
결국.
데이터 기반 테스트
테스트 케이스 내에서 루프를보고 싶지 않습니다. Boost Test에는 다른 데이터로 테스트를 반복합니까? 대부분의 테스트 프레임 워크는 그렇습니다. 부스트에서 가져옵니다.