summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2022-03-04 13:38:36 +0000
committerHåvard Pettersen <havardpe@oath.com>2022-03-05 15:00:58 +0000
commit2681bcd99a024d0e94c2cddd08b7636818773a73 (patch)
treefe8466205ba79ea6b7ab89008247070f88cd918f /vespalib
parentbeed3becc8ec1abe88aea8aa88e6e703fb67dc3c (diff)
gc old process code
also added read_line function to new Process code
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/CMakeLists.txt1
-rw-r--r--vespalib/src/tests/assert/assert_test.cpp21
-rw-r--r--vespalib/src/tests/child_process/.gitignore4
-rw-r--r--vespalib/src/tests/child_process/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/child_process/child_process_test.cpp187
-rw-r--r--vespalib/src/tests/drop-file-from-cache/drop_file_from_cache_test.cpp21
-rw-r--r--vespalib/src/tests/exception_classes/silenceuncaught_test.cpp39
-rw-r--r--vespalib/src/tests/host_name/host_name_test.cpp3
-rw-r--r--vespalib/src/tests/make_fixture_macros/make_fixture_macros_test.cpp12
-rw-r--r--vespalib/src/tests/process/process_test.cpp40
-rw-r--r--vespalib/src/tests/tutorial/make_tutorial.cpp46
-rw-r--r--vespalib/src/vespa/vespalib/process/process.cpp17
-rw-r--r--vespalib/src/vespa/vespalib/process/process.h2
-rw-r--r--vespalib/src/vespa/vespalib/testkit/test_macros.h36
-rw-r--r--vespalib/src/vespa/vespalib/testkit/testapp.h8
-rw-r--r--vespalib/src/vespa/vespalib/util/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/util/child_process.cpp346
-rw-r--r--vespalib/src/vespa/vespalib/util/child_process.h212
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