diff options
Diffstat (limited to 'vespalib')
18 files changed, 139 insertions, 865 deletions
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt index 80308a75bd5..6fb832b21d3 100644 --- a/vespalib/CMakeLists.txt +++ b/vespalib/CMakeLists.txt @@ -29,7 +29,6 @@ vespa_define_module( src/tests/btree/btree_store src/tests/btree/btree-scan-speed src/tests/btree/btree-stress - src/tests/child_process src/tests/component src/tests/compress src/tests/compression diff --git a/vespalib/src/tests/assert/assert_test.cpp b/vespalib/src/tests/assert/assert_test.cpp index 49f4d2194f4..e953fc439c3 100644 --- a/vespalib/src/tests/assert/assert_test.cpp +++ b/vespalib/src/tests/assert/assert_test.cpp @@ -1,6 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/child_process.h> +#include <vespa/vespalib/process/process.h> #include <vespa/vespalib/util/stringfmt.h> #include <vespa/vespalib/util/assert.h> #include <vespa/vespalib/io/fileutil.h> @@ -16,24 +16,21 @@ TEST("that it borks the first time.") { vespalib::rmdir("var", true); ASSERT_TRUE(vespalib::mkdir(assertDir, true)); { - ChildProcess proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000"); - proc.wait(); - ASSERT_EQUAL(proc.getExitCode() & 0x7f, 6); + Process proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000"); + ASSERT_EQUAL(proc.join() & 0x7f, 6); } { - ChildProcess proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000"); - proc.readLine(assertName); - proc.wait(); - ASSERT_EQUAL(proc.getExitCode() & 0x7f, 0); + Process proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000"); + assertName = proc.read_line(); + ASSERT_EQUAL(proc.join() & 0x7f, 0); } ASSERT_EQUAL(0, unlink(assertName.c_str())); { - ChildProcess proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000"); - proc.wait(); - ASSERT_EQUAL(proc.getExitCode() & 0x7f, 6); + Process proc("ulimit -c 0 && exec env VESPA_HOME=./ ./vespalib_asserter_app myassert 10000"); + ASSERT_EQUAL(proc.join() & 0x7f, 6); } ASSERT_EQUAL(0, unlink(assertName.c_str())); ASSERT_TRUE(vespalib::rmdir("var", true)); } -TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/child_process/.gitignore b/vespalib/src/tests/child_process/.gitignore deleted file mode 100644 index 7e094c772a6..00000000000 --- a/vespalib/src/tests/child_process/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.depend -Makefile -child_process_test -vespalib_child_process_test_app diff --git a/vespalib/src/tests/child_process/CMakeLists.txt b/vespalib/src/tests/child_process/CMakeLists.txt deleted file mode 100644 index b0503f7b08c..00000000000 --- a/vespalib/src/tests/child_process/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(vespalib_child_process_test_app TEST - SOURCES - child_process_test.cpp - DEPENDS - vespalib -) -vespa_add_test(NAME vespalib_child_process_test_app COMMAND vespalib_child_process_test_app COST 30) diff --git a/vespalib/src/tests/child_process/child_process_test.cpp b/vespalib/src/tests/child_process/child_process_test.cpp deleted file mode 100644 index d8ed707c1bf..00000000000 --- a/vespalib/src/tests/child_process/child_process_test.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/child_process.h> - -using vespalib::ChildProcess; - -TEST("simple run, ignore output") { - EXPECT_TRUE(ChildProcess::run("echo foo")); -} - -TEST("simple run, ignore output, failure") { - EXPECT_TRUE(!ChildProcess::run("false")); -} - -TEST("simple run, ignore output, timeout") { - EXPECT_TRUE(!ChildProcess::run("exec sleep 60", 10)); -} - -TEST("simple run") { - std::string out; - EXPECT_TRUE(ChildProcess::run("/bin/echo -n foo", out)); - EXPECT_EQUAL(out, "foo"); -} - -TEST("simple run, strip single-line trailing newline") { - std::string out; - EXPECT_TRUE(ChildProcess::run("echo foo", out)); - EXPECT_EQUAL(out, "foo"); -} - -TEST("simple run, don't strip multi-line output") { - std::string out; - EXPECT_TRUE(ChildProcess::run("perl -e 'print \"foo\\n\\n\"'", out)); - EXPECT_EQUAL(out, "foo\n\n"); -} - -TEST("simple run with input") { - std::string in = "bar"; - std::string out; - EXPECT_TRUE(ChildProcess::run(in, "cat", out)); - EXPECT_EQUAL(out, "bar"); -} - -TEST("simple run with input, strip single-line trailing newline") { - std::string in = "bar\n"; - std::string out; - EXPECT_TRUE(ChildProcess::run(in, "cat", out)); - EXPECT_EQUAL(out, "bar"); -} - -TEST("simple run with input, don't strip multi-line output") { - std::string in = "bar\n\n"; - std::string out; - EXPECT_TRUE(ChildProcess::run(in, "cat", out)); - EXPECT_EQUAL("bar\n\n", out); -} - -TEST_MT("simple run, partial output due to timeout", 2) { - std::string out; - std::vector<size_t> timeouts({150, 300, 3000, 6000, 60000}); - const char *my_cmd = "exec perl -e '$| = 1; print \"foo\\\n\"; sleep(600); print \"bar\\\n\"'"; - for (size_t timeout: timeouts) { - fprintf(stderr, "... verifying partial output with%s input (timeout = %zu)\n", - (thread_id == 0) ? "out" : "", timeout); - if (thread_id == 0) { - out.clear(); - EXPECT_TRUE(!ChildProcess::run(my_cmd, out, timeout)); - } else { - out.clear(); - std::string in = "ignored\n"; - EXPECT_TRUE(!ChildProcess::run(in, my_cmd, out, timeout)); - } - if (out == "foo") { - break; - } - } - EXPECT_EQUAL(out, "foo"); -} - -TEST("proc failure") { - ChildProcess proc("false"); - // read with length 0 will wait for output - EXPECT_TRUE(proc.read(NULL, 0) == 0); - EXPECT_TRUE(proc.wait(60000)); - EXPECT_TRUE(!proc.running()); - EXPECT_TRUE(proc.failed()); -} - -TEST("basic read/write") { - int x; - int read; - char buf[64]; - ChildProcess proc("cat"); - - EXPECT_TRUE(proc.running()); - EXPECT_TRUE(!proc.failed()); - EXPECT_TRUE(proc.write("foo", 3)); - for (x = 0, read = 0; x < 10 && read < 3; ++x) { - read += proc.read(buf + read, sizeof(buf) - read); - } - EXPECT_TRUE(read == 3 && memcmp(buf, "foo", 3) == 0); - EXPECT_TRUE(proc.write("bar!", 4)); - for (x = 0, read = 0; x < 10 && read < 4; ++x) { - read += proc.read(buf + read, sizeof(buf) - read); - } - EXPECT_TRUE(read == 4 && memcmp(buf, "bar!", 4) == 0); - EXPECT_TRUE(!proc.eof()); // not eof yet - EXPECT_TRUE(proc.close()); // close stdin - EXPECT_TRUE(!proc.eof()); // eof not detected yet - EXPECT_TRUE(proc.read(buf, sizeof(buf)) == 0); - EXPECT_TRUE(proc.eof()); - EXPECT_TRUE(proc.read(buf, sizeof(buf)) == 0); - EXPECT_TRUE(proc.wait(60000)); - EXPECT_TRUE(!proc.running()); - EXPECT_TRUE(!proc.failed()); -} - -TEST("continuos run, readLine") { - std::string str; - ChildProcess proc("cat"); - - EXPECT_TRUE(proc.running()); - EXPECT_TRUE(!proc.failed()); - EXPECT_TRUE(proc.write("foo\n", 4)); - EXPECT_TRUE(proc.readLine(str)); - EXPECT_EQUAL(str, "foo"); - EXPECT_TRUE(proc.write("bar!\n", 5)); - EXPECT_TRUE(proc.readLine(str)); - EXPECT_EQUAL(str, "bar!"); - EXPECT_TRUE(!proc.eof()); // not eof yet - EXPECT_TRUE(proc.close()); // close stdin - EXPECT_TRUE(!proc.eof()); // eof not detected yet - EXPECT_TRUE(!proc.readLine(str)); - EXPECT_EQUAL(str, ""); - EXPECT_TRUE(proc.eof()); - EXPECT_TRUE(!proc.readLine(str)); - EXPECT_EQUAL(str, ""); - EXPECT_TRUE(proc.wait(60000)); - EXPECT_TRUE(!proc.running()); - EXPECT_TRUE(!proc.failed()); -} - -TEST("readLine, eof flushes last line") { - std::string str; - ChildProcess proc("cat"); - - EXPECT_TRUE(proc.running()); - EXPECT_TRUE(!proc.failed()); - EXPECT_TRUE(proc.write("foo\n", 4)); - EXPECT_TRUE(proc.readLine(str)); - EXPECT_EQUAL(str, "foo"); - EXPECT_TRUE(proc.write("bar!", 4)); - EXPECT_TRUE(!proc.eof()); // not eof yet - EXPECT_TRUE(proc.close()); // close stdin - EXPECT_TRUE(!proc.eof()); // eof not detected yet - EXPECT_TRUE(proc.readLine(str)); - EXPECT_EQUAL(str, "bar!"); - EXPECT_TRUE(proc.eof()); - EXPECT_TRUE(!proc.readLine(str)); - EXPECT_EQUAL(str, ""); - EXPECT_TRUE(proc.wait(60000)); - EXPECT_TRUE(!proc.running()); - EXPECT_TRUE(!proc.failed()); -} - -TEST("long continuos run, readLine") { - std::string in; - std::string out; - ChildProcess proc("cat"); - - EXPECT_TRUE(proc.running()); - EXPECT_TRUE(!proc.failed()); - for (uint32_t i = 0; i < 10000; ++i) { - char num[32]; - sprintf(num, "%d", i); - in.assign("long continous run, line "); - in.append(num).append("\n"); - EXPECT_TRUE(proc.write(in.data(), in.length())); - in.erase(in.size() - 1, 1); - EXPECT_TRUE(proc.readLine(out)); - EXPECT_EQUAL(in, out); - } - EXPECT_TRUE(proc.running()); - EXPECT_TRUE(!proc.failed()); -} - -TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp b/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp index e3344fb4106..63cec1caee1 100644 --- a/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp +++ b/vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp @@ -1,25 +1,22 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/child_process.h> +#include <vespa/vespalib/process/process.h> -using vespalib::ChildProcess; +using vespalib::Process; TEST("no arguments") { - ChildProcess drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache"); - drop.wait(); - EXPECT_EQUAL(1, drop.getExitCode()); + Process drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache"); + EXPECT_EQUAL(1, drop.join()); } TEST("file does not exist") { - ChildProcess drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache not_exist"); - drop.wait(); - EXPECT_EQUAL(2, drop.getExitCode()); + Process drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache not_exist"); + EXPECT_EQUAL(2, drop.join()); } TEST("All is well") { - ChildProcess drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache vespalib_drop_file_from_cache_test_app"); - drop.wait(); - EXPECT_EQUAL(0, drop.getExitCode()); + Process drop("../../apps/vespa-drop-file-from-cache/vespa-drop-file-from-cache vespalib_drop_file_from_cache_test_app"); + EXPECT_EQUAL(0, drop.join()); } -TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp b/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp index 6c757b00af6..a15e9327d16 100644 --- a/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp +++ b/vespalib/src/tests/exception_classes/silenceuncaught_test.cpp @@ -1,7 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/vespalib/util/exception.h> -#include <vespa/vespalib/util/child_process.h> +#include <vespa/vespalib/process/process.h> using namespace vespalib; @@ -14,27 +14,23 @@ using namespace vespalib; #endif TEST("that uncaught exception causes negative exitcode.") { - ChildProcess proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught"); - proc.wait(); - EXPECT_LESS(proc.getExitCode(), 0); + Process proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught"); + EXPECT_LESS(proc.join(), 0); } TEST("that uncaught silenced exception causes exitcode 66") { - ChildProcess proc("exec ./vespalib_caught_uncaught_app silenced_and_uncaught"); - proc.wait(); - EXPECT_EQUAL(proc.getExitCode(), 66); + Process proc("exec ./vespalib_caught_uncaught_app silenced_and_uncaught"); + EXPECT_EQUAL(proc.join(), 66); } TEST("that caught silenced exception followed by an uncaught causes negative exitcode.") { - ChildProcess proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught_after_silenced_and_caught"); - proc.wait(); - EXPECT_LESS(proc.getExitCode(), 0); + Process proc("ulimit -c 0 && exec ./vespalib_caught_uncaught_app uncaught_after_silenced_and_caught"); + EXPECT_LESS(proc.join(), 0); } TEST("that caught silenced exception causes exitcode 0") { - ChildProcess proc("exec ./vespalib_caught_uncaught_app silenced_and_caught"); - proc.wait(); - EXPECT_EQUAL(proc.getExitCode(), 0); + Process proc("exec ./vespalib_caught_uncaught_app silenced_and_caught"); + EXPECT_EQUAL(proc.join(), 0); } #ifndef __SANITIZE_ADDRESS__ @@ -42,23 +38,20 @@ TEST("that caught silenced exception causes exitcode 0") { // setrlimit with RLIMIT_AS is broken on Darwin #else TEST("that mmap within limits are fine cause exitcode 0") { - ChildProcess proc("exec ./vespalib_mmap_app 150000000 10485760 1"); - proc.wait(); - EXPECT_EQUAL(proc.getExitCode(), 0); + Process proc("exec ./vespalib_mmap_app 150000000 10485760 1"); + EXPECT_EQUAL(proc.join(), 0); } TEST("that mmap beyond limits cause negative exitcode.") { - ChildProcess proc("ulimit -c 0 && exec ./vespalib_mmap_app 100000000 10485760 10"); - proc.wait(); - EXPECT_LESS(proc.getExitCode(), 0); + Process proc("ulimit -c 0 && exec ./vespalib_mmap_app 100000000 10485760 10"); + EXPECT_LESS(proc.join(), 0); } TEST("that mmap beyond limits with set VESPA_SILENCE_CORE_ON_OOM cause exitcode 66.") { - ChildProcess proc("VESPA_SILENCE_CORE_ON_OOM=1 exec ./vespalib_mmap_app 100000000 10485760 10"); - proc.wait(); - EXPECT_EQUAL(proc.getExitCode(), 66); + Process proc("VESPA_SILENCE_CORE_ON_OOM=1 exec ./vespalib_mmap_app 100000000 10485760 10"); + EXPECT_EQUAL(proc.join(), 66); } #endif #endif -TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/host_name/host_name_test.cpp b/vespalib/src/tests/host_name/host_name_test.cpp index ca5aebe8c95..b68762cebb3 100644 --- a/vespalib/src/tests/host_name/host_name_test.cpp +++ b/vespalib/src/tests/host_name/host_name_test.cpp @@ -1,7 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/vespalib/util/host_name.h> -#include <vespa/vespalib/util/child_process.h> using namespace vespalib; @@ -9,4 +8,4 @@ TEST("require that host name can be obtained") { EXPECT_NOT_EQUAL("", HostName::get()); } -TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp b/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp index 0264a5aad0e..1cddddf7edc 100644 --- a/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp +++ b/vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp @@ -1,12 +1,12 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/child_process.h> +#include <vespa/vespalib/process/process.h> using namespace vespalib; -bool runPrint(const char *cmd) { - std::string out; - bool res = ChildProcess::run(cmd, out); +bool runPrint(const vespalib::string &cmd) { + vespalib::string out; + bool res = Process::run(cmd, out); fprintf(stderr, "%s", out.c_str()); return res; } @@ -15,9 +15,9 @@ TEST("make fixture macros") { EXPECT_FALSE(runPrint("../../apps/make_fixture_macros/vespalib_make_fixture_macros_app")); EXPECT_TRUE(runPrint("../../apps/make_fixture_macros/vespalib_make_fixture_macros_app 9 > macros.tmp")); - std::string diffCmd("diff -u "); + vespalib::string diffCmd("diff -u "); diffCmd += TEST_PATH("../../vespa/vespalib/testkit/generated_fixture_macros.h macros.tmp"); EXPECT_TRUE(runPrint(diffCmd.c_str())); } -TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); } +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/process/process_test.cpp b/vespalib/src/tests/process/process_test.cpp index 5f22e74ae4d..ec91bad4369 100644 --- a/vespalib/src/tests/process/process_test.cpp +++ b/vespalib/src/tests/process/process_test.cpp @@ -66,6 +66,46 @@ TEST(ProcessTest, proc_kill) { //----------------------------------------------------------------------------- +vespalib::string line1 = "this is a line"; +vespalib::string line2 = "this is also a line"; +vespalib::string line3 = "this is last line"; + +TEST(ProcessTest, read_line) { + Process proc("cat"); + for (const vespalib::string &line: {std::cref(line1), std::cref(line2), std::cref(line3)}) { + auto mem = proc.reserve(line.size() + 1); + memcpy(mem.data, line.data(), line.size()); + mem.data[line.size()] = '\n'; + proc.commit(line.size() + 1); + fprintf(stderr, "write: %s\n", line.c_str()); + auto res = proc.read_line(); + fprintf(stderr, "read: %s\n", line.c_str()); + EXPECT_EQ(res, line); + EXPECT_FALSE(proc.eof()); + } + proc.close(); + EXPECT_EQ(proc.read_line(), ""); + EXPECT_TRUE(proc.eof()); + EXPECT_EQ(proc.join(), 0); +} + +TEST(ProcessTest, read_line_without_newline) { + Process proc("cat"); + const auto &line = line3; + auto mem = proc.reserve(line.size()); + memcpy(mem.data, line.data(), line.size()); + proc.commit(line.size()); + fprintf(stderr, "write: %s\n", line.c_str()); + proc.close(); // need eof to flush line + auto res = proc.read_line(); + fprintf(stderr, "read: %s\n", line.c_str()); + EXPECT_EQ(res, line); + EXPECT_TRUE(proc.eof()); + EXPECT_EQ(proc.join(), 0); +} + +//----------------------------------------------------------------------------- + void write_slime(const Slime &slime, Output &out) { JsonFormat::encode(slime, out, true); out.reserve(1).data[0] = '\n'; diff --git a/vespalib/src/tests/tutorial/make_tutorial.cpp b/vespalib/src/tests/tutorial/make_tutorial.cpp index 46292a81005..58e3f529405 100644 --- a/vespalib/src/tests/tutorial/make_tutorial.cpp +++ b/vespalib/src/tests/tutorial/make_tutorial.cpp @@ -1,6 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/child_process.h> +#include <vespa/vespalib/process/process.h> #include <vespa/vespalib/util/stringfmt.h> #include <sys/mman.h> #include <sys/stat.h> @@ -10,48 +10,48 @@ using namespace vespalib; -std::string readFile(const std::string &filename) { +vespalib::string readFile(const vespalib::string &filename) { TEST_STATE(filename.c_str()); MappedFileInput file(filename); ASSERT_TRUE(file.valid()); Memory data = file.get(); - return std::string(data.data, data.size); + return vespalib::string(data.data, data.size); } -std::string runCommand(const std::string &cmd) { - std::string out; - ASSERT_TRUE(ChildProcess::run(cmd.c_str(), out)); +vespalib::string runCommand(const vespalib::string &cmd) { + vespalib::string out; + ASSERT_TRUE(Process::run(cmd, out)); return out; } -void insertExample(const std::string &name, const std::string &src_dir) { - std::string str = runCommand(make_string("%s/make_example.sh %s", src_dir.c_str(), +void insertExample(const vespalib::string &name, const vespalib::string &src_dir) { + vespalib::string str = runCommand(make_string("%s/make_example.sh %s", src_dir.c_str(), name.c_str())); fprintf(stdout, "%s", str.c_str()); } -void insertSource(const std::string &name, const std::string &src_dir) { - std::string str = runCommand(make_string("%s/make_source.sh %s", src_dir.c_str(), +void insertSource(const vespalib::string &name, const vespalib::string &src_dir) { + vespalib::string str = runCommand(make_string("%s/make_source.sh %s", src_dir.c_str(), name.c_str())); fprintf(stdout, "%s", str.c_str()); } -void insertFile(const std::string &name, const std::string &src_dir) { - std::string str = readFile(src_dir + "/" + name); +void insertFile(const vespalib::string &name, const vespalib::string &src_dir) { + vespalib::string str = readFile(src_dir + "/" + name); fprintf(stdout, "%s", str.c_str()); } -TEST_MAIN_WITH_PROCESS_PROXY() { - std::string pre("[insert:"); - std::string example("example:"); - std::string source("source:"); - std::string file("file:"); - std::string post("]\n"); +TEST_MAIN() { + vespalib::string pre("[insert:"); + vespalib::string example("example:"); + vespalib::string source("source:"); + vespalib::string file("file:"); + vespalib::string post("]\n"); size_t pos = 0; size_t end = 0; size_t cursor = 0; - std::string input = readFile(TEST_PATH("tutorial_source.html")); + vespalib::string input = readFile(TEST_PATH("tutorial_source.html")); while ((pos = input.find(pre, cursor)) < input.size() && (end = input.find(post, pos)) < input.size()) { @@ -59,15 +59,15 @@ TEST_MAIN_WITH_PROCESS_PROXY() { pos += pre.size(); if (input.find(example, pos) == pos) { pos += example.size(); - insertExample(std::string((input.data() + pos), (end - pos)), TEST_PATH("")); + insertExample(vespalib::string((input.data() + pos), (end - pos)), TEST_PATH("")); } else if (input.find(source, pos) == pos) { pos += source.size(); - insertSource(std::string((input.data() + pos), (end - pos)), TEST_PATH("")); + insertSource(vespalib::string((input.data() + pos), (end - pos)), TEST_PATH("")); } else if (input.find(file, pos) == pos) { pos += file.size(); - insertFile(std::string((input.data() + pos), (end - pos)), TEST_PATH("")); + insertFile(vespalib::string((input.data() + pos), (end - pos)), TEST_PATH("")); } else { - std::string str((input.data() + pos), (end - pos)); + vespalib::string str((input.data() + pos), (end - pos)); TEST_FATAL(make_string("invalid directive >%s<", str.c_str()).c_str()); } cursor = end + post.size(); diff --git a/vespalib/src/vespa/vespalib/process/process.cpp b/vespalib/src/vespa/vespalib/process/process.cpp index 3b202a830f5..7749ffdff65 100644 --- a/vespalib/src/vespa/vespalib/process/process.cpp +++ b/vespalib/src/vespa/vespalib/process/process.cpp @@ -104,6 +104,23 @@ Process::commit(size_t bytes) return *this; } +vespalib::string +Process::read_line() { + vespalib::string line; + for (auto mem = obtain(); (mem.size > 0); mem = obtain()) { + for (size_t i = 0; i < mem.size; ++i) { + if (mem.data[i] == '\n') { + evict(i + 1); + return line; + } else { + line.push_back(mem.data[i]); + } + } + evict(mem.size); + } + return line; +} + int Process::join() { diff --git a/vespalib/src/vespa/vespalib/process/process.h b/vespalib/src/vespa/vespalib/process/process.h index 97771752faa..d15784f5d31 100644 --- a/vespalib/src/vespa/vespalib/process/process.h +++ b/vespalib/src/vespa/vespalib/process/process.h @@ -43,6 +43,8 @@ public: Input &evict(size_t bytes) override; // Input (stdout) WritableMemory reserve(size_t bytes) override; // Output (stdin) Output &commit(size_t bytes) override; // Output (stdin) + vespalib::string read_line(); + bool eof() const { return _eof; } int join(); ~Process(); diff --git a/vespalib/src/vespa/vespalib/testkit/test_macros.h b/vespalib/src/vespa/vespalib/testkit/test_macros.h index 5ee8e170ef0..ebf3e06d283 100644 --- a/vespalib/src/vespa/vespalib/testkit/test_macros.h +++ b/vespalib/src/vespa/vespalib/testkit/test_macros.h @@ -18,28 +18,24 @@ #define TEST_TRACE() TEST_MASTER.trace(__FILE__, __LINE__) #define TEST_THREAD(name) TEST_MASTER.setThreadName(name) #define TEST_BARRIER() TEST_MASTER.awaitThreadBarrier(__FILE__, __LINE__) -#define TEST_MAIN_IMPL(useProxy) \ - void test_kit_main(); \ - struct TestKitApp : FastOS_Application \ - { \ - bool useProcessStarter() const override { return useProxy; } \ - int Main() override; \ - }; \ - int main(int argc, char **argv) \ - { \ - TestKitApp app; \ - return app.Entry(argc, argv); \ - } \ - int TestKitApp::Main() { \ - TEST_MASTER.init(__FILE__); \ - test_kit_main(); \ - return (TEST_MASTER.fini() ? 0 : 1); \ - } \ +#define TEST_MAIN() \ + void test_kit_main(); \ + struct TestKitApp : FastOS_Application \ + { \ + int Main() override; \ + }; \ + int main(int argc, char **argv) \ + { \ + TestKitApp app; \ + return app.Entry(argc, argv); \ + } \ + int TestKitApp::Main() { \ + TEST_MASTER.init(__FILE__); \ + test_kit_main(); \ + return (TEST_MASTER.fini() ? 0 : 1); \ + } \ void test_kit_main() -#define TEST_MAIN() TEST_MAIN_IMPL(false) -#define TEST_MAIN_WITH_PROCESS_PROXY() TEST_MAIN_IMPL(true) - //----------------------------------------------------------------------------- #include "generated_fixture_macros.h" //----------------------------------------------------------------------------- diff --git a/vespalib/src/vespa/vespalib/testkit/testapp.h b/vespalib/src/vespa/vespalib/testkit/testapp.h index facb0857e8c..8ffb9958555 100644 --- a/vespalib/src/vespa/vespalib/testkit/testapp.h +++ b/vespalib/src/vespa/vespalib/testkit/testapp.h @@ -22,14 +22,6 @@ public: int Main() override; \ }; \ TEST_APPHOOK(test) -#define TEST_SETUP_WITHPROCESSPROXY(test) \ - class test : public vespalib::TestApp \ - { \ - public: \ - int Main(); \ - virtual bool useProcessStarter() const { return true; } \ - }; \ - TEST_APPHOOK(test) namespace vespalib { diff --git a/vespalib/src/vespa/vespalib/util/CMakeLists.txt b/vespalib/src/vespa/vespalib/util/CMakeLists.txt index 747ed736aad..f7bdd4427e3 100644 --- a/vespalib/src/vespa/vespalib/util/CMakeLists.txt +++ b/vespalib/src/vespa/vespalib/util/CMakeLists.txt @@ -14,7 +14,6 @@ vespa_add_library(vespalib_vespalib_util OBJECT binary_hamming_distance.cpp blockingthreadstackexecutor.cpp box.cpp - child_process.cpp classname.cpp compress.cpp compressor.cpp diff --git a/vespalib/src/vespa/vespalib/util/child_process.cpp b/vespalib/src/vespa/vespalib/util/child_process.cpp deleted file mode 100644 index 93db56cdf67..00000000000 --- a/vespalib/src/vespa/vespalib/util/child_process.cpp +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "guard.h" -#include "child_process.h" -#include <cstring> -#include <vespa/vespalib/util/size_literals.h> - -namespace vespalib { - -namespace child_process { - -using namespace std::chrono; - -/** - * @brief ChildProcess internal timeout management. - **/ -class Timer -{ -private: - const steady_clock::time_point _startTime; - const int64_t _maxTimeMS; - milliseconds _elapsed; - -public: - Timer(int64_t maxTimeMS) - : _startTime(steady_clock::now()), - _maxTimeMS(maxTimeMS), - _elapsed(0) - { } - Timer &update() { - _elapsed = duration_cast<milliseconds>(steady_clock::now() - _startTime); - return *this; - } - int64_t elapsed() const { - return _elapsed.count(); - } - int64_t remaining() const { - if (_maxTimeMS == -1) { - return -1; - } - if (elapsed() > _maxTimeMS) { - return 0; - } - return (_maxTimeMS - _elapsed.count()); - } - int64_t waitTime() const { - int res = remaining(); - if (res >= 0 && res <= 10000) { - return res; - } - return 10000; - } - bool timeOut() const { - return (remaining() == 0); - } -}; - -} // namespace child_process - - -void -ChildProcess::Reader::OnReceiveData(const void *data, size_t length) -{ - const char *buf = (const char *) data; - std::unique_lock lock(_lock); - if (_gotEOF || (buf != nullptr && length == 0)) { // ignore special cases - return; - } - if (buf == nullptr) { // EOF - if (--_num_streams == 0) { - _gotEOF = true; - } - } else { - _queue.push(std::string(buf, length)); - } - if (_waitCnt > 0) { - _cond.notify_one(); - } -} - - -bool -ChildProcess::Reader::hasData() -{ - // NB: caller has lock on _cond - return (!_data.empty() || !_queue.empty()); -} - - -bool -ChildProcess::Reader::waitForData(child_process::Timer &timer, std::unique_lock<std::mutex> &guard) -{ - // NB: caller has lock on _cond - CounterGuard count(_waitCnt); - while (!timer.update().timeOut() && !hasData() && !_gotEOF) { - _cond.wait_for(guard, std::chrono::milliseconds(timer.waitTime())); - } - return hasData(); -} - - -void -ChildProcess::Reader::updateEOF() -{ - // NB: caller has lock on _cond - if (_data.empty() && _queue.empty() && _gotEOF) { - _readEOF = true; - } -} - - -ChildProcess::Reader::Reader(int num_streams) - : _lock(), - _cond(), - _queue(), - _data(), - _num_streams(num_streams), - _gotEOF(false), - _waitCnt(0), - _readEOF(false) -{ -} - - -ChildProcess::Reader::~Reader() = default; - - -uint32_t -ChildProcess::Reader::read(char *buf, uint32_t len, int msTimeout) -{ - if (eof()) { - return 0; - } - child_process::Timer timer(msTimeout); - std::unique_lock guard(_lock); - waitForData(timer, guard); - uint32_t bytes = 0; - while (bytes < len && hasData()) { - if (_data.empty()) { - _data = _queue.front(); - _queue.pop(); - } - if (len - bytes < _data.length()) { - memcpy(buf + bytes, _data.data(), len - bytes); - _data.erase(0, len - bytes); - bytes = len; - } else { - memcpy(buf + bytes, _data.data(), _data.length()); - bytes += _data.length(); - _data.clear(); - } - } - updateEOF(); - return bytes; -} - - -bool -ChildProcess::Reader::readLine(std::string &line, int msTimeout) -{ - line.clear(); - if (eof()) { - return false; - } - child_process::Timer timer(msTimeout); - std::unique_lock guard(_lock); - while (waitForData(timer, guard)) { - while (hasData()) { - if (_data.empty()) { - _data = _queue.front(); - _queue.pop(); - } - std::string::size_type ofs = _data.find('\n'); - if (ofs == std::string::npos) { - line.append(_data); - _data.clear(); - } else { - line.append(_data, 0, ofs); - _data.erase(0, ofs + 1); - updateEOF(); - return true; - } - } - } - updateEOF(); - if (eof()) { - return !line.empty(); - } - _data.swap(line); - return false; -} - -//----------------------------------------------------------------------------- - -void -ChildProcess::checkProc() -{ - if (_running) { - bool stillRunning; - if (_proc.PollWait(&_exitCode, &stillRunning) && !stillRunning) { - _running = false; - _failed = (_exitCode != 0); - } - } -} - - -ChildProcess::ChildProcess(const char *cmd) - : _reader(1), - _proc(cmd, &_reader), - _running(false), - _failed(false), - _exitCode(-918273645) -{ - _running = _proc.CreateWithShell(); - _failed = !_running; -} - -ChildProcess::ChildProcess(const char *cmd, capture_stderr_tag) - : _reader(2), - _proc(cmd, &_reader, &_reader), - _running(false), - _failed(false), - _exitCode(-918273645) -{ - _running = _proc.CreateWithShell(); - _failed = !_running; -} - - -ChildProcess::~ChildProcess() = default; - - -bool -ChildProcess::write(const char *buf, uint32_t len) -{ - if (len == 0) { - return true; - } - return _proc.WriteStdin(buf, len); -} - - -bool -ChildProcess::close() -{ - return _proc.WriteStdin(nullptr, 0); -} - - -uint32_t -ChildProcess::read(char *buf, uint32_t len, int msTimeout) -{ - return _reader.read(buf, len, msTimeout); -} - - -bool -ChildProcess::readLine(std::string &line, int msTimeout) -{ - return _reader.readLine(line, msTimeout); -} - - -bool -ChildProcess::wait(int msTimeout) -{ - bool done = true; - checkProc(); - if (_running) { - if (msTimeout != -1) { - msTimeout = (msTimeout + 999) / 1000; - } - if (_proc.Wait(&_exitCode, msTimeout)) { - _failed = (_exitCode != 0); - } else { - _failed = true; - done = false; - } - _running = false; - } - return done; -} - - -bool -ChildProcess::running() -{ - checkProc(); - return _running; -} - - -bool -ChildProcess::failed() -{ - checkProc(); - return _failed; -} - -int -ChildProcess::getExitCode() -{ - return _exitCode; -} - - -bool -ChildProcess::run(const std::string &input, const char *cmd, - std::string &output, int msTimeout) -{ - ChildProcess proc(cmd); - child_process::Timer timer(msTimeout); - char buf[4_Ki]; - proc.write(input.data(), input.length()); - proc.close(); // close stdin - while (!proc.eof() && !timer.timeOut()) { - uint32_t res = proc.read(buf, sizeof(buf), timer.remaining()); - output.append(buf, res); - timer.update(); - } - if ( ! output.empty() && output.find('\n') == output.size() - 1) { - output.erase(output.size() - 1, 1); - } - proc.wait(timer.update().remaining()); - return (!proc.running() && !proc.failed()); -} - - -bool -ChildProcess::run(const char *cmd, std::string &output, int msTimeout) -{ - std::string input; // empty input - return run(input, cmd, output, msTimeout); -} - - -bool -ChildProcess::run(const char *cmd, int msTimeout) -{ - std::string input; // empty input - std::string output; // ignore output - return run(input, cmd, output, msTimeout); -} - -} // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/util/child_process.h b/vespalib/src/vespa/vespalib/util/child_process.h deleted file mode 100644 index 877c56a8cb1..00000000000 --- a/vespalib/src/vespa/vespalib/util/child_process.h +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#pragma once - -#include <vespa/fastos/process.h> -#ifndef FASTOS_NO_THREADS -#include <string> -#include <queue> -#include <condition_variable> - -namespace vespalib::child_process { class Timer; } - -namespace vespalib { -/** - * @brief Child Process utility class for running external programs - * - * Designed for use in unit tests and other places - * where you need to run, control and communicate with - * some external program. - **/ -class ChildProcess -{ -private: - class Reader : public FastOS_ProcessRedirectListener - { - private: - std::mutex _lock; - std::condition_variable _cond; - std::queue<std::string> _queue; - std::string _data; - int _num_streams; - bool _gotEOF; - int _waitCnt; - bool _readEOF; - - void OnReceiveData(const void *data, size_t length) override; - bool hasData(); - bool waitForData(child_process::Timer &timer, std::unique_lock<std::mutex> &lock); - void updateEOF(); - - public: - Reader(int num_streams); - ~Reader() override; - - uint32_t read(char *buf, uint32_t len, int msTimeout); - bool readLine(std::string &line, int msTimeout); - bool eof() const { return _readEOF; }; - }; - - Reader _reader; - FastOS_Process _proc; - bool _running; - bool _failed; - int _exitCode; - - void checkProc(); - -public: - ChildProcess(const ChildProcess &) = delete; - ChildProcess &operator=(const ChildProcess &) = delete; - struct capture_stderr_tag{}; - - /** - * @brief Run a child process - * - * Starts a process running the given command - * @param cmd A shell command line to run - **/ - explicit ChildProcess(const char *cmd); - - /** - * @brief Run a child process - * - * Starts a process running the given command. stderr is - * redirected into stdout. - * @param cmd A shell command line to run - **/ - explicit ChildProcess(const char *cmd, capture_stderr_tag); - - /** @brief destructor doing cleanup if needed */ - ~ChildProcess(); - - /** - * @return process id - **/ - pid_t getPid() { return _proc.GetProcessId(); } - - /** - * @brief send data as input to the running process - * - * The given data will be sent so it becomes - * available on the running process's standard input. - * - * @param buf the data containing len bytes to be sent - * @param len the number of bytes to send - * @return true if successful - **/ - bool write(const char *buf, uint32_t len); - - /** - * @brief close the running process's standard input - * - * when running a program that consumes stdin, - * make sure to call this method to signal - * that it can finish. - * @return true if successful - **/ - bool close(); - - /** - * @brief read program output - * - * If the running program writes data to its standard output, you - * can and should get the data with read() or readLine() calls. - * - * @param buf pointer where data is stored - * @param len number of bytes to try to read - * @param msTimeout number of milliseconds to wait for data - **/ - uint32_t read(char *buf, uint32_t len, int msTimeout = 10000); - - /** - * @brief read a line of program output - * - * See read(). - * @param line reference to a string where a line of program output will be stored - * @param msTimeout number of milliseconds to wait for data - * @return true if successful - **/ - bool readLine(std::string &line, int msTimeout = 10000); - - /** - * @brief check if the program has finished writing output - * @return true if standard output from the process is closed - **/ - bool eof() const { return _reader.eof(); } - - /** - * @brief wait for the program to exit - * @param msTimeout milliseconds to wait; the default (-1) will wait forever - * @return true if the program exited, false on timeout - **/ - bool wait(int msTimeout = -1); - - /** @brief check if the program is still running */ - bool running(); - - /** - * @brief get the exit code of the started program. - * - * Will return the stored exitcode. - * It assumes that the command is done. - * @return exit code. - **/ - int getExitCode(); - - /** - * @brief check if program failed - * - * Check if we failed to run the program or the program finished with - * a non-zero exit status. - * @return true if something went wrong - **/ - bool failed(); - - /** - * @brief run a command - * - * Utility function that runs the given command, sends input, and - * loops reading output until the program finishes or the timeout - * expires. - * Any final terminating newline will be erased from output, - * just like for shell backticks. - * - * @param input The input the program will receive - * @param cmd The command to run - * @param output Any output will be appended to this string - * @param msTimeout milliseconds timeout; -1 means wait forever for program to finish - **/ - static bool run(const std::string &input, const char *cmd, - std::string &output, int msTimeout = -1); - /** - * @brief run a command - * - * Utility function that runs the given command with no input, and - * loops reading output until the program finishes or the timeout - * expires. - * Any final terminating newline will be erased from output, - * just like for shell backticks. - * - * @param cmd The command to run - * @param output Any output will be appended to this string - * @param msTimeout milliseconds timeout; -1 means wait forever for program to finish - **/ - static bool run(const char *cmd, std::string &output, int msTimeout = -1); - - /** - * @brief run a command - * - * Utility function that runs the given command with no input, and - * loops reading output until the program finishes or the timeout - * expires. Output (if any) is ignored. - * - * @param cmd The command to run - * @param msTimeout milliseconds timeout; -1 means wait forever for program to finish - **/ - static bool run(const char *cmd, int msTimeout = -1); -}; - -} // namespace vespalib - -#endif // FASTOS_NO_THREADS |