blob: 6c0dcb2f1199cf9c8254d6036ef35df1148fadf7 [file] [log] [blame]
Darin Petkov85d02b72011-05-17 13:25:51 -07001// Copyright (c) 2011 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"
11#include <glib.h>
12#include <gtest/gtest.h>
13#include "update_engine/subprocess.h"
14#include "update_engine/test_utils.h"
15#include "update_engine/utils.h"
16
17using std::string;
18using std::vector;
19
20namespace chromeos_update_engine {
21
22class SubprocessTest : public ::testing::Test {
23 protected:
24 bool callback_done;
25};
26
27namespace {
Darin Petkovf67bb1f2010-11-08 16:10:26 -080028const int kLocalHttpPort = 8088;
adlr@google.com3defe6a2009-12-04 20:57:17 +000029
Darin Petkov6f03a3b2010-11-10 14:27:14 -080030void Callback(int return_code, const string& output, void *p) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -070031 EXPECT_EQ(1, return_code);
adlr@google.com3defe6a2009-12-04 20:57:17 +000032 GMainLoop* loop = reinterpret_cast<GMainLoop*>(p);
33 g_main_loop_quit(loop);
34}
35
Darin Petkov6f03a3b2010-11-10 14:27:14 -080036void CallbackEcho(int return_code, const string& output, void *p) {
37 EXPECT_EQ(0, return_code);
38 EXPECT_NE(string::npos, output.find("this is stdout"));
39 EXPECT_NE(string::npos, output.find("this is stderr"));
40 GMainLoop* loop = reinterpret_cast<GMainLoop*>(p);
41 g_main_loop_quit(loop);
42}
43
adlr@google.com3defe6a2009-12-04 20:57:17 +000044gboolean LaunchFalseInMainLoop(gpointer data) {
45 vector<string> cmd;
46 cmd.push_back("/bin/false");
47 Subprocess::Get().Exec(cmd, Callback, data);
48 return FALSE;
49}
Darin Petkov6f03a3b2010-11-10 14:27:14 -080050
51gboolean LaunchEchoInMainLoop(gpointer data) {
52 vector<string> cmd;
53 cmd.push_back("/bin/sh");
54 cmd.push_back("-c");
55 cmd.push_back("echo this is stdout; echo this is stderr > /dev/stderr");
56 Subprocess::Get().Exec(cmd, CallbackEcho, data);
57 return FALSE;
58}
adlr@google.com3defe6a2009-12-04 20:57:17 +000059} // namespace {}
60
61TEST(SubprocessTest, SimpleTest) {
62 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
63 g_timeout_add(0, &LaunchFalseInMainLoop, loop);
64 g_main_loop_run(loop);
65 g_main_loop_unref(loop);
66}
67
Darin Petkov6f03a3b2010-11-10 14:27:14 -080068TEST(SubprocessTest, EchoTest) {
69 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
70 g_timeout_add(0, &LaunchEchoInMainLoop, loop);
71 g_main_loop_run(loop);
72 g_main_loop_unref(loop);
73}
74
Darin Petkov85d02b72011-05-17 13:25:51 -070075TEST(SubprocessTest, SynchronousEchoTest) {
76 vector<string> cmd;
77 cmd.push_back("/bin/sh");
78 cmd.push_back("-c");
79 cmd.push_back("echo -n stdout-here; echo -n stderr-there > /dev/stderr");
80 int rc = -1;
81 string stdout;
82 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
83 EXPECT_EQ(0, rc);
84 EXPECT_EQ("stdout-herestderr-there", stdout);
85}
86
87TEST(SubprocessTest, SynchronousEchoNoOutputTest) {
88 vector<string> cmd;
89 cmd.push_back("/bin/sh");
90 cmd.push_back("-c");
91 cmd.push_back("echo test");
92 int rc = -1;
93 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, NULL));
94 EXPECT_EQ(0, rc);
95}
96
adlr@google.com3defe6a2009-12-04 20:57:17 +000097namespace {
Darin Petkov6f03a3b2010-11-10 14:27:14 -080098void CallbackBad(int return_code, const string& output, void *p) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000099 CHECK(false) << "should never be called.";
100}
101
102struct CancelTestData {
103 bool spawned;
104 GMainLoop *loop;
105};
106
107gboolean StartAndCancelInRunLoop(gpointer data) {
108 CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
109 vector<string> cmd;
110 cmd.push_back("./test_http_server");
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700111 uint32_t tag = Subprocess::Get().Exec(cmd, CallbackBad, NULL);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000112 EXPECT_NE(0, tag);
113 cancel_test_data->spawned = true;
114 printf("spawned\n");
115 // Wait for server to be up and running
Darin Petkov27fa9c52010-07-15 15:11:55 -0700116 useconds_t total_wait_time = 0;
117 const useconds_t kMaxWaitTime = 3 * 1000000; // 3 seconds
adlr@google.com3defe6a2009-12-04 20:57:17 +0000118 for (;;) {
119 int status =
120 System(StringPrintf("wget -O /dev/null http://127.0.0.1:%d/foo",
121 kLocalHttpPort));
122 EXPECT_NE(-1, status) << "system() failed";
123 EXPECT_TRUE(WIFEXITED(status))
124 << "command failed to run or died abnormally";
125 if (0 == WEXITSTATUS(status))
126 break;
Darin Petkov27fa9c52010-07-15 15:11:55 -0700127
128 const useconds_t kSleepTime = 100 * 1000; // 100ms
129 usleep(kSleepTime); // 100 ms
130 total_wait_time += kSleepTime;
131 CHECK_LT(total_wait_time, kMaxWaitTime);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000132 }
133 Subprocess::Get().CancelExec(tag);
134 return FALSE;
135}
136} // namespace {}
137
138gboolean ExitWhenDone(gpointer data) {
139 CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
140 if (cancel_test_data->spawned && !Subprocess::Get().SubprocessInFlight()) {
141 // tear down the sub process
142 printf("tear down time\n");
Darin Petkovb7de1d52010-08-24 13:38:33 -0700143 int status = System(
144 StringPrintf("wget -O /dev/null http://127.0.0.1:%d/quitquitquit",
145 kLocalHttpPort));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000146 EXPECT_NE(-1, status) << "system() failed";
147 EXPECT_TRUE(WIFEXITED(status))
148 << "command failed to run or died abnormally";
149 g_main_loop_quit(cancel_test_data->loop);
150 return FALSE;
151 }
152 return TRUE;
153}
154
155TEST(SubprocessTest, CancelTest) {
156 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
157 CancelTestData cancel_test_data;
158 cancel_test_data.spawned = false;
159 cancel_test_data.loop = loop;
160 g_timeout_add(100, &StartAndCancelInRunLoop, &cancel_test_data);
161 g_timeout_add(10, &ExitWhenDone, &cancel_test_data);
162 g_main_loop_run(loop);
163 g_main_loop_unref(loop);
164 printf("here\n");
165}
166
167} // namespace chromeos_update_engine