108334c51SBrooks Davis // Copyright 2014 The Kyua Authors.
208334c51SBrooks Davis // All rights reserved.
308334c51SBrooks Davis //
408334c51SBrooks Davis // Redistribution and use in source and binary forms, with or without
508334c51SBrooks Davis // modification, are permitted provided that the following conditions are
608334c51SBrooks Davis // met:
708334c51SBrooks Davis //
808334c51SBrooks Davis // * Redistributions of source code must retain the above copyright
908334c51SBrooks Davis // notice, this list of conditions and the following disclaimer.
1008334c51SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
1108334c51SBrooks Davis // notice, this list of conditions and the following disclaimer in the
1208334c51SBrooks Davis // documentation and/or other materials provided with the distribution.
1308334c51SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
1408334c51SBrooks Davis // may be used to endorse or promote products derived from this software
1508334c51SBrooks Davis // without specific prior written permission.
1608334c51SBrooks Davis //
1708334c51SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1808334c51SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1908334c51SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2008334c51SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2108334c51SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2208334c51SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2308334c51SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2408334c51SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2508334c51SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2608334c51SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2708334c51SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2808334c51SBrooks Davis
2908334c51SBrooks Davis #include "engine/plain.hpp"
3008334c51SBrooks Davis
3108334c51SBrooks Davis extern "C" {
3208334c51SBrooks Davis #include <unistd.h>
3308334c51SBrooks Davis }
3408334c51SBrooks Davis
3508334c51SBrooks Davis #include <cstdlib>
3608334c51SBrooks Davis
37257e70f1SIgor Ostapenko #include "engine/execenv/execenv.hpp"
3808334c51SBrooks Davis #include "model/test_case.hpp"
3908334c51SBrooks Davis #include "model/test_program.hpp"
4008334c51SBrooks Davis #include "model/test_result.hpp"
4108334c51SBrooks Davis #include "utils/defs.hpp"
4208334c51SBrooks Davis #include "utils/env.hpp"
4308334c51SBrooks Davis #include "utils/format/macros.hpp"
4408334c51SBrooks Davis #include "utils/fs/path.hpp"
4508334c51SBrooks Davis #include "utils/optional.ipp"
4608334c51SBrooks Davis #include "utils/process/operations.hpp"
4708334c51SBrooks Davis #include "utils/process/status.hpp"
4808334c51SBrooks Davis #include "utils/sanity.hpp"
4908334c51SBrooks Davis
5008334c51SBrooks Davis namespace config = utils::config;
51257e70f1SIgor Ostapenko namespace execenv = engine::execenv;
5208334c51SBrooks Davis namespace fs = utils::fs;
5308334c51SBrooks Davis namespace process = utils::process;
5408334c51SBrooks Davis
5508334c51SBrooks Davis using utils::optional;
5608334c51SBrooks Davis
5708334c51SBrooks Davis
5808334c51SBrooks Davis /// Executes a test program's list operation.
5908334c51SBrooks Davis ///
6008334c51SBrooks Davis /// This method is intended to be called within a subprocess and is expected
6108334c51SBrooks Davis /// to terminate execution either by exec(2)ing the test program or by
6208334c51SBrooks Davis /// exiting with a failure.
6308334c51SBrooks Davis void
exec_list(const model::test_program &,const config::properties_map &) const6408334c51SBrooks Davis engine::plain_interface::exec_list(
6508334c51SBrooks Davis const model::test_program& /* test_program */,
6608334c51SBrooks Davis const config::properties_map& /* vars */) const
6708334c51SBrooks Davis {
6808334c51SBrooks Davis ::_exit(EXIT_SUCCESS);
6908334c51SBrooks Davis }
7008334c51SBrooks Davis
7108334c51SBrooks Davis
7208334c51SBrooks Davis /// Computes the test cases list of a test program.
7308334c51SBrooks Davis ///
7408334c51SBrooks Davis /// \return A list of test cases.
7508334c51SBrooks Davis model::test_cases_map
parse_list(const optional<process::status> &,const fs::path &,const fs::path &) const7608334c51SBrooks Davis engine::plain_interface::parse_list(
7708334c51SBrooks Davis const optional< process::status >& /* status */,
7808334c51SBrooks Davis const fs::path& /* stdout_path */,
7908334c51SBrooks Davis const fs::path& /* stderr_path */) const
8008334c51SBrooks Davis {
8108334c51SBrooks Davis return model::test_cases_map_builder().add("main").build();
8208334c51SBrooks Davis }
8308334c51SBrooks Davis
8408334c51SBrooks Davis
8508334c51SBrooks Davis /// Executes a test case of the test program.
8608334c51SBrooks Davis ///
8708334c51SBrooks Davis /// This method is intended to be called within a subprocess and is expected
8808334c51SBrooks Davis /// to terminate execution either by exec(2)ing the test program or by
8908334c51SBrooks Davis /// exiting with a failure.
9008334c51SBrooks Davis ///
9108334c51SBrooks Davis /// \param test_program The test program to execute.
9208334c51SBrooks Davis /// \param test_case_name Name of the test case to invoke.
9308334c51SBrooks Davis /// \param vars User-provided variables to pass to the test program.
9408334c51SBrooks Davis void
exec_test(const model::test_program & test_program,const std::string & test_case_name,const config::properties_map & vars,const fs::path &) const9508334c51SBrooks Davis engine::plain_interface::exec_test(
9608334c51SBrooks Davis const model::test_program& test_program,
9708334c51SBrooks Davis const std::string& test_case_name,
9808334c51SBrooks Davis const config::properties_map& vars,
9908334c51SBrooks Davis const fs::path& /* control_directory */) const
10008334c51SBrooks Davis {
10108334c51SBrooks Davis PRE(test_case_name == "main");
10208334c51SBrooks Davis
10308334c51SBrooks Davis for (config::properties_map::const_iterator iter = vars.begin();
10408334c51SBrooks Davis iter != vars.end(); ++iter) {
10508334c51SBrooks Davis utils::setenv(F("TEST_ENV_%s") % (*iter).first, (*iter).second);
10608334c51SBrooks Davis }
10708334c51SBrooks Davis
10808334c51SBrooks Davis process::args_vector args;
109257e70f1SIgor Ostapenko
110257e70f1SIgor Ostapenko auto e = execenv::get(test_program, test_case_name);
111257e70f1SIgor Ostapenko e->init();
112257e70f1SIgor Ostapenko e->exec(args);
11347fb5d2bSBrooks Davis __builtin_unreachable();
11408334c51SBrooks Davis }
11508334c51SBrooks Davis
11608334c51SBrooks Davis
11708334c51SBrooks Davis /// Computes the result of a test case based on its termination status.
11808334c51SBrooks Davis ///
11908334c51SBrooks Davis /// \param status The termination status of the subprocess used to execute
12008334c51SBrooks Davis /// the exec_test() method or none if the test timed out.
12108334c51SBrooks Davis ///
12208334c51SBrooks Davis /// \return A test result.
12308334c51SBrooks Davis model::test_result
compute_result(const optional<process::status> & status,const fs::path &,const fs::path &,const fs::path &) const12408334c51SBrooks Davis engine::plain_interface::compute_result(
12508334c51SBrooks Davis const optional< process::status >& status,
12608334c51SBrooks Davis const fs::path& /* control_directory */,
12708334c51SBrooks Davis const fs::path& /* stdout_path */,
12808334c51SBrooks Davis const fs::path& /* stderr_path */) const
12908334c51SBrooks Davis {
13008334c51SBrooks Davis if (!status) {
13108334c51SBrooks Davis return model::test_result(model::test_result_broken,
13208334c51SBrooks Davis "Test case timed out");
13308334c51SBrooks Davis }
13408334c51SBrooks Davis
13508334c51SBrooks Davis if (status.get().exited()) {
13608334c51SBrooks Davis const int exitstatus = status.get().exitstatus();
13708334c51SBrooks Davis if (exitstatus == EXIT_SUCCESS) {
13808334c51SBrooks Davis return model::test_result(model::test_result_passed);
13908334c51SBrooks Davis } else {
14008334c51SBrooks Davis return model::test_result(
14108334c51SBrooks Davis model::test_result_failed,
14208334c51SBrooks Davis F("Returned non-success exit status %s") % exitstatus);
14308334c51SBrooks Davis }
14408334c51SBrooks Davis } else {
14508334c51SBrooks Davis return model::test_result(
14608334c51SBrooks Davis model::test_result_broken,
14708334c51SBrooks Davis F("Received signal %s") % status.get().termsig());
14808334c51SBrooks Davis }
14908334c51SBrooks Davis }
150