blob: ae67fbb8e104b7bbce9d990a6eb8411fbc562da0 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8#include <string>
9#include <vector>
10#include "base/string_util.h"
Mike Frysinger8155d082012-04-06 15:23:18 -040011#include <base/stringprintf.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000012#include <glib.h>
13#include <gtest/gtest.h>
14#include "update_engine/subprocess.h"
15#include "update_engine/test_utils.h"
16#include "update_engine/utils.h"
17
18using std::string;
19using std::vector;
20
21namespace chromeos_update_engine {
22
23class SubprocessTest : public ::testing::Test {
24 protected:
25 bool callback_done;
26};
27
28namespace {
Darin Petkovf67bb1f2010-11-08 16:10:26 -080029const int kLocalHttpPort = 8088;
adlr@google.com3defe6a2009-12-04 20:57:17 +000030
Darin Petkov6f03a3b2010-11-10 14:27:14 -080031void Callback(int return_code, const string& output, void *p) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -070032 EXPECT_EQ(1, return_code);
adlr@google.com3defe6a2009-12-04 20:57:17 +000033 GMainLoop* loop = reinterpret_cast<GMainLoop*>(p);
34 g_main_loop_quit(loop);
35}
36
Darin Petkov6f03a3b2010-11-10 14:27:14 -080037void CallbackEcho(int return_code, const string& output, void *p) {
38 EXPECT_EQ(0, return_code);
39 EXPECT_NE(string::npos, output.find("this is stdout"));
40 EXPECT_NE(string::npos, output.find("this is stderr"));
41 GMainLoop* loop = reinterpret_cast<GMainLoop*>(p);
42 g_main_loop_quit(loop);
43}
44
adlr@google.com3defe6a2009-12-04 20:57:17 +000045gboolean LaunchFalseInMainLoop(gpointer data) {
46 vector<string> cmd;
47 cmd.push_back("/bin/false");
48 Subprocess::Get().Exec(cmd, Callback, data);
49 return FALSE;
50}
Darin Petkov6f03a3b2010-11-10 14:27:14 -080051
52gboolean LaunchEchoInMainLoop(gpointer data) {
53 vector<string> cmd;
54 cmd.push_back("/bin/sh");
55 cmd.push_back("-c");
56 cmd.push_back("echo this is stdout; echo this is stderr > /dev/stderr");
57 Subprocess::Get().Exec(cmd, CallbackEcho, data);
58 return FALSE;
59}
adlr@google.com3defe6a2009-12-04 20:57:17 +000060} // namespace {}
61
62TEST(SubprocessTest, SimpleTest) {
63 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
64 g_timeout_add(0, &LaunchFalseInMainLoop, loop);
65 g_main_loop_run(loop);
66 g_main_loop_unref(loop);
67}
68
Darin Petkov6f03a3b2010-11-10 14:27:14 -080069TEST(SubprocessTest, EchoTest) {
70 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
71 g_timeout_add(0, &LaunchEchoInMainLoop, loop);
72 g_main_loop_run(loop);
73 g_main_loop_unref(loop);
74}
75
Darin Petkov85d02b72011-05-17 13:25:51 -070076TEST(SubprocessTest, SynchronousEchoTest) {
77 vector<string> cmd;
78 cmd.push_back("/bin/sh");
79 cmd.push_back("-c");
80 cmd.push_back("echo -n stdout-here; echo -n stderr-there > /dev/stderr");
81 int rc = -1;
82 string stdout;
83 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
84 EXPECT_EQ(0, rc);
85 EXPECT_EQ("stdout-herestderr-there", stdout);
86}
87
88TEST(SubprocessTest, SynchronousEchoNoOutputTest) {
89 vector<string> cmd;
90 cmd.push_back("/bin/sh");
91 cmd.push_back("-c");
92 cmd.push_back("echo test");
93 int rc = -1;
94 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, NULL));
95 EXPECT_EQ(0, rc);
96}
97
adlr@google.com3defe6a2009-12-04 20:57:17 +000098namespace {
Darin Petkov6f03a3b2010-11-10 14:27:14 -080099void CallbackBad(int return_code, const string& output, void *p) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000100 CHECK(false) << "should never be called.";
101}
102
103struct CancelTestData {
104 bool spawned;
105 GMainLoop *loop;
106};
107
108gboolean StartAndCancelInRunLoop(gpointer data) {
109 CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
110 vector<string> cmd;
111 cmd.push_back("./test_http_server");
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700112 uint32_t tag = Subprocess::Get().Exec(cmd, CallbackBad, NULL);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000113 EXPECT_NE(0, tag);
114 cancel_test_data->spawned = true;
115 printf("spawned\n");
116 // Wait for server to be up and running
Darin Petkov27fa9c52010-07-15 15:11:55 -0700117 useconds_t total_wait_time = 0;
118 const useconds_t kMaxWaitTime = 3 * 1000000; // 3 seconds
adlr@google.com3defe6a2009-12-04 20:57:17 +0000119 for (;;) {
120 int status =
121 System(StringPrintf("wget -O /dev/null http://127.0.0.1:%d/foo",
122 kLocalHttpPort));
123 EXPECT_NE(-1, status) << "system() failed";
124 EXPECT_TRUE(WIFEXITED(status))
125 << "command failed to run or died abnormally";
126 if (0 == WEXITSTATUS(status))
127 break;
Darin Petkov27fa9c52010-07-15 15:11:55 -0700128
129 const useconds_t kSleepTime = 100 * 1000; // 100ms
130 usleep(kSleepTime); // 100 ms
131 total_wait_time += kSleepTime;
132 CHECK_LT(total_wait_time, kMaxWaitTime);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000133 }
134 Subprocess::Get().CancelExec(tag);
135 return FALSE;
136}
137} // namespace {}
138
139gboolean ExitWhenDone(gpointer data) {
140 CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
141 if (cancel_test_data->spawned && !Subprocess::Get().SubprocessInFlight()) {
142 // tear down the sub process
143 printf("tear down time\n");
Darin Petkovb7de1d52010-08-24 13:38:33 -0700144 int status = System(
145 StringPrintf("wget -O /dev/null http://127.0.0.1:%d/quitquitquit",
146 kLocalHttpPort));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000147 EXPECT_NE(-1, status) << "system() failed";
148 EXPECT_TRUE(WIFEXITED(status))
149 << "command failed to run or died abnormally";
150 g_main_loop_quit(cancel_test_data->loop);
151 return FALSE;
152 }
153 return TRUE;
154}
155
156TEST(SubprocessTest, CancelTest) {
157 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
158 CancelTestData cancel_test_data;
159 cancel_test_data.spawned = false;
160 cancel_test_data.loop = loop;
161 g_timeout_add(100, &StartAndCancelInRunLoop, &cancel_test_data);
162 g_timeout_add(10, &ExitWhenDone, &cancel_test_data);
163 g_main_loop_run(loop);
164 g_main_loop_unref(loop);
165 printf("here\n");
166}
167
168} // namespace chromeos_update_engine