blob: d23040d9c1eb59f990e38f5654f75477b2b793ad [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>
Gilad Arnold8e3f1262013-01-08 14:59:54 -08008
adlr@google.com3defe6a2009-12-04 20:57:17 +00009#include <string>
10#include <vector>
Gilad Arnold8e3f1262013-01-08 14:59:54 -080011
12#include <base/string_util.h>
Mike Frysinger8155d082012-04-06 15:23:18 -040013#include <base/stringprintf.h>
Gilad Arnold8e3f1262013-01-08 14:59:54 -080014#include <base/time.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000015#include <glib.h>
16#include <gtest/gtest.h>
Gilad Arnold8e3f1262013-01-08 14:59:54 -080017
adlr@google.com3defe6a2009-12-04 20:57:17 +000018#include "update_engine/subprocess.h"
19#include "update_engine/test_utils.h"
20#include "update_engine/utils.h"
21
Gilad Arnold8e3f1262013-01-08 14:59:54 -080022using base::TimeDelta;
adlr@google.com3defe6a2009-12-04 20:57:17 +000023using std::string;
24using std::vector;
25
26namespace chromeos_update_engine {
27
28class SubprocessTest : public ::testing::Test {
29 protected:
30 bool callback_done;
31};
32
33namespace {
Darin Petkovf67bb1f2010-11-08 16:10:26 -080034const int kLocalHttpPort = 8088;
adlr@google.com3defe6a2009-12-04 20:57:17 +000035
Darin Petkov6f03a3b2010-11-10 14:27:14 -080036void Callback(int return_code, const string& output, void *p) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -070037 EXPECT_EQ(1, return_code);
adlr@google.com3defe6a2009-12-04 20:57:17 +000038 GMainLoop* loop = reinterpret_cast<GMainLoop*>(p);
39 g_main_loop_quit(loop);
40}
41
Darin Petkov6f03a3b2010-11-10 14:27:14 -080042void CallbackEcho(int return_code, const string& output, void *p) {
43 EXPECT_EQ(0, return_code);
44 EXPECT_NE(string::npos, output.find("this is stdout"));
45 EXPECT_NE(string::npos, output.find("this is stderr"));
46 GMainLoop* loop = reinterpret_cast<GMainLoop*>(p);
47 g_main_loop_quit(loop);
48}
49
adlr@google.com3defe6a2009-12-04 20:57:17 +000050gboolean LaunchFalseInMainLoop(gpointer data) {
51 vector<string> cmd;
52 cmd.push_back("/bin/false");
53 Subprocess::Get().Exec(cmd, Callback, data);
54 return FALSE;
55}
Darin Petkov6f03a3b2010-11-10 14:27:14 -080056
57gboolean LaunchEchoInMainLoop(gpointer data) {
58 vector<string> cmd;
59 cmd.push_back("/bin/sh");
60 cmd.push_back("-c");
61 cmd.push_back("echo this is stdout; echo this is stderr > /dev/stderr");
62 Subprocess::Get().Exec(cmd, CallbackEcho, data);
63 return FALSE;
64}
adlr@google.com3defe6a2009-12-04 20:57:17 +000065} // namespace {}
66
67TEST(SubprocessTest, SimpleTest) {
68 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
69 g_timeout_add(0, &LaunchFalseInMainLoop, loop);
70 g_main_loop_run(loop);
71 g_main_loop_unref(loop);
72}
73
Darin Petkov6f03a3b2010-11-10 14:27:14 -080074TEST(SubprocessTest, EchoTest) {
75 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
76 g_timeout_add(0, &LaunchEchoInMainLoop, loop);
77 g_main_loop_run(loop);
78 g_main_loop_unref(loop);
79}
80
Darin Petkov85d02b72011-05-17 13:25:51 -070081TEST(SubprocessTest, SynchronousEchoTest) {
82 vector<string> cmd;
83 cmd.push_back("/bin/sh");
84 cmd.push_back("-c");
85 cmd.push_back("echo -n stdout-here; echo -n stderr-there > /dev/stderr");
86 int rc = -1;
87 string stdout;
88 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
89 EXPECT_EQ(0, rc);
90 EXPECT_EQ("stdout-herestderr-there", stdout);
91}
92
93TEST(SubprocessTest, SynchronousEchoNoOutputTest) {
94 vector<string> cmd;
95 cmd.push_back("/bin/sh");
96 cmd.push_back("-c");
97 cmd.push_back("echo test");
98 int rc = -1;
99 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, NULL));
100 EXPECT_EQ(0, rc);
101}
102
adlr@google.com3defe6a2009-12-04 20:57:17 +0000103namespace {
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800104void CallbackBad(int return_code, const string& output, void *p) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000105 CHECK(false) << "should never be called.";
106}
107
108struct CancelTestData {
109 bool spawned;
110 GMainLoop *loop;
111};
112
113gboolean StartAndCancelInRunLoop(gpointer data) {
114 CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
115 vector<string> cmd;
116 cmd.push_back("./test_http_server");
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700117 uint32_t tag = Subprocess::Get().Exec(cmd, CallbackBad, NULL);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000118 EXPECT_NE(0, tag);
119 cancel_test_data->spawned = true;
120 printf("spawned\n");
121 // Wait for server to be up and running
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800122 TimeDelta total_wait_time;
123 const TimeDelta kSleepTime = TimeDelta::FromMilliseconds(100);
124 const TimeDelta kMaxWaitTime = TimeDelta::FromSeconds(3);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000125 for (;;) {
126 int status =
127 System(StringPrintf("wget -O /dev/null http://127.0.0.1:%d/foo",
128 kLocalHttpPort));
129 EXPECT_NE(-1, status) << "system() failed";
130 EXPECT_TRUE(WIFEXITED(status))
131 << "command failed to run or died abnormally";
132 if (0 == WEXITSTATUS(status))
133 break;
Darin Petkov27fa9c52010-07-15 15:11:55 -0700134
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800135 g_usleep(kSleepTime.InMicroseconds());
Darin Petkov27fa9c52010-07-15 15:11:55 -0700136 total_wait_time += kSleepTime;
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800137 CHECK_LT(total_wait_time.InMicroseconds(), kMaxWaitTime.InMicroseconds());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000138 }
139 Subprocess::Get().CancelExec(tag);
140 return FALSE;
141}
142} // namespace {}
143
144gboolean ExitWhenDone(gpointer data) {
145 CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
146 if (cancel_test_data->spawned && !Subprocess::Get().SubprocessInFlight()) {
147 // tear down the sub process
148 printf("tear down time\n");
Darin Petkovb7de1d52010-08-24 13:38:33 -0700149 int status = System(
150 StringPrintf("wget -O /dev/null http://127.0.0.1:%d/quitquitquit",
151 kLocalHttpPort));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000152 EXPECT_NE(-1, status) << "system() failed";
153 EXPECT_TRUE(WIFEXITED(status))
154 << "command failed to run or died abnormally";
155 g_main_loop_quit(cancel_test_data->loop);
156 return FALSE;
157 }
158 return TRUE;
159}
160
161TEST(SubprocessTest, CancelTest) {
162 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
163 CancelTestData cancel_test_data;
164 cancel_test_data.spawned = false;
165 cancel_test_data.loop = loop;
166 g_timeout_add(100, &StartAndCancelInRunLoop, &cancel_test_data);
167 g_timeout_add(10, &ExitWhenDone, &cancel_test_data);
168 g_main_loop_run(loop);
169 g_main_loop_unref(loop);
170 printf("here\n");
171}
172
173} // namespace chromeos_update_engine