popen_unittest.cpp 3.95 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved

// Author: Zhangyi Chen (chenzhangyi01@baidu.com)
// Date: 2017/11/06 10:57:08

#include "butil/popen.h"
#include "butil/errno.h"
#include "butil/strings/string_piece.h"
9
#include "butil/build_config.h"
Zhangyi Chen's avatar
Zhangyi Chen committed
10
#include <gtest/gtest.h>
11

12 13 14 15 16
namespace butil {
extern int read_command_output_through_clone(std::ostream&, const char*);
extern int read_command_output_through_popen(std::ostream&, const char*);
}

17 18 19 20 21
namespace {

class PopenTest : public testing::Test {
};

22 23 24 25 26 27 28 29 30
TEST(PopenTest, posix_popen) {
    std::ostringstream oss;
    int rc = butil::read_command_output_through_popen(oss, "echo \"Hello World\"");
    ASSERT_EQ(0, rc) << berror(errno);
    ASSERT_EQ("Hello World\n", oss.str());

    oss.str("");
    rc = butil::read_command_output_through_popen(oss, "exit 1");
    EXPECT_EQ(1, rc) << berror(errno);
31
    ASSERT_TRUE(oss.str().empty()) << oss.str();
32 33 34 35 36 37
    oss.str("");
    rc = butil::read_command_output_through_popen(oss, "kill -9 $$");
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
    oss.str("");
38
    rc = butil::read_command_output_through_popen(oss, "kill -15 $$");
39 40 41 42
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));

43 44
    // TODO(zhujiashun): Fix this in macos
    /*
45
    oss.str("");
46
     ASSERT_EQ(0, butil::read_command_output_through_popen(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
47 48 49 50
    ASSERT_EQ(100000u, oss.str().length());
    std::string expected;
    expected.resize(100000, '=');
    ASSERT_EQ(expected, oss.str());
51
    */
52 53 54 55 56
}

#if defined(OS_LINUX)

TEST(PopenTest, clone) {
57
    std::ostringstream oss;
58
    int rc = butil::read_command_output_through_clone(oss, "echo \"Hello World\"");
59 60 61 62
    ASSERT_EQ(0, rc) << berror(errno);
    ASSERT_EQ("Hello World\n", oss.str());

    oss.str("");
63
    rc = butil::read_command_output_through_clone(oss, "exit 1");
64
    ASSERT_EQ(1, rc) << berror(errno);
65
    ASSERT_TRUE(oss.str().empty()) << oss.str();
66
    oss.str("");
67
    rc = butil::read_command_output_through_clone(oss, "kill -9 $$");
68 69 70 71
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
    oss.str("");
72
    rc = butil::read_command_output_through_clone(oss, "kill -15 $$");
73 74 75 76 77
    ASSERT_EQ(-1, rc);
    ASSERT_EQ(errno, ECHILD);
    ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));

    oss.str("");
78 79
    ASSERT_EQ(0, butil::read_command_output_through_clone(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
    ASSERT_EQ(100000u, oss.str().length());
80 81 82 83 84
    std::string expected;
    expected.resize(100000, '=');
    ASSERT_EQ(expected, oss.str());
}

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
struct CounterArg {
    volatile int64_t counter;
    volatile bool stop;
};

static void* counter_thread(void* args) {
    CounterArg* ca = (CounterArg*)args;
    while (!ca->stop) {
        ++ca->counter;
    }
    return NULL;
}

static int fork_thread(void* arg) {
    usleep(100 * 1000);
    _exit(0);
}

const int CHILD_STACK_SIZE = 64 * 1024;

TEST(PopenTest, does_vfork_suspend_all_threads) {
    pthread_t tid;
    CounterArg ca = { 0 , false };
    ASSERT_EQ(0, pthread_create(&tid, NULL, counter_thread, &ca));
    usleep(100 * 1000);
    char* child_stack_mem = (char*)malloc(CHILD_STACK_SIZE);
    void* child_stack = child_stack_mem + CHILD_STACK_SIZE;  
    const int64_t counter_before_fork = ca.counter;
    pid_t cpid = clone(fork_thread, child_stack, CLONE_VFORK, NULL);
    const int64_t counter_after_fork = ca.counter;
    usleep(100 * 1000);
    const int64_t counter_after_sleep = ca.counter;
    int ws;
    ca.stop = true;
    pthread_join(tid, NULL);
    std::cout << "bc=" << counter_before_fork << " ac=" << counter_after_fork
              << " as=" << counter_after_sleep
              << std::endl;
    ASSERT_EQ(cpid, waitpid(cpid, &ws, __WALL));
}

#endif  // OS_LINUX

128
}