1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include <sys/wait.h>
17 
18 #include "tensorflow/core/lib/core/status_test_util.h"
19 #include "tensorflow/core/platform/subprocess.h"
20 #include "tensorflow/core/platform/test.h"
21 
22 namespace tensorflow {
23 
24 class SubProcessTest : public ::testing::Test {};
25 
TEST_F(SubProcessTest,NoOutputNoComm)26 TEST_F(SubProcessTest, NoOutputNoComm) {
27   tensorflow::SubProcess proc;
28   proc.SetProgram("/bin/cat", {"cat", "/dev/null"});
29   EXPECT_TRUE(proc.Start());
30   EXPECT_TRUE(proc.Wait());
31 }
32 
TEST_F(SubProcessTest,NoOutput)33 TEST_F(SubProcessTest, NoOutput) {
34   tensorflow::SubProcess proc;
35   proc.SetProgram("/bin/cat", {"cat", "/dev/null"});
36   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
37   proc.SetChannelAction(CHAN_STDERR, ACTION_PIPE);
38   EXPECT_TRUE(proc.Start());
39 
40   string out, err;
41   int status = proc.Communicate(nullptr, &out, &err);
42   EXPECT_TRUE(WIFEXITED(status));
43   EXPECT_EQ(0, WEXITSTATUS(status));
44   EXPECT_EQ("", out);
45   EXPECT_EQ("", err);
46 }
47 
TEST_F(SubProcessTest,Stdout)48 TEST_F(SubProcessTest, Stdout) {
49   tensorflow::SubProcess proc;
50   proc.SetProgram("/bin/echo", {"echo", "-n", "hello world"});
51   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
52   proc.SetChannelAction(CHAN_STDERR, ACTION_PIPE);
53   EXPECT_TRUE(proc.Start());
54 
55   string out, err;
56   int status = proc.Communicate(nullptr, &out, &err);
57   EXPECT_TRUE(WIFEXITED(status));
58   EXPECT_EQ(0, WEXITSTATUS(status));
59   EXPECT_EQ("hello world", out);
60   EXPECT_EQ("", err);
61 }
62 
TEST_F(SubProcessTest,StdoutIgnored)63 TEST_F(SubProcessTest, StdoutIgnored) {
64   tensorflow::SubProcess proc;
65   proc.SetProgram("/bin/echo", {"echo", "-n", "hello world"});
66   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
67   proc.SetChannelAction(CHAN_STDERR, ACTION_PIPE);
68   EXPECT_TRUE(proc.Start());
69 
70   int status = proc.Communicate(nullptr, nullptr, nullptr);
71   EXPECT_TRUE(WIFEXITED(status));
72   EXPECT_EQ(0, WEXITSTATUS(status));
73 }
74 
TEST_F(SubProcessTest,Stderr)75 TEST_F(SubProcessTest, Stderr) {
76   tensorflow::SubProcess proc;
77   proc.SetProgram("/bin/cat", {"cat", "/file_does_not_exist"});
78   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
79   proc.SetChannelAction(CHAN_STDERR, ACTION_PIPE);
80   EXPECT_TRUE(proc.Start());
81 
82   string out, err;
83   int status = proc.Communicate(nullptr, &out, &err);
84   EXPECT_TRUE(WIFEXITED(status));
85   EXPECT_EQ(1, WEXITSTATUS(status));
86   EXPECT_EQ("", out);
87   EXPECT_NE(string::npos, err.find("/file_does_not_exist"));
88 }
89 
TEST_F(SubProcessTest,StderrIgnored)90 TEST_F(SubProcessTest, StderrIgnored) {
91   tensorflow::SubProcess proc;
92   proc.SetProgram("/bin/cat", {"cat", "/file_does_not_exist"});
93   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
94   proc.SetChannelAction(CHAN_STDERR, ACTION_PIPE);
95   EXPECT_TRUE(proc.Start());
96 
97   int status = proc.Communicate(nullptr, nullptr, nullptr);
98   EXPECT_TRUE(WIFEXITED(status));
99   EXPECT_EQ(1, WEXITSTATUS(status));
100 }
101 
TEST_F(SubProcessTest,Stdin)102 TEST_F(SubProcessTest, Stdin) {
103   tensorflow::SubProcess proc;
104   proc.SetProgram("/usr/bin/wc", {"wc", "-l"});
105   proc.SetChannelAction(CHAN_STDIN, ACTION_PIPE);
106   EXPECT_TRUE(proc.Start());
107 
108   string in = "foobar\nbarfoo\nhaha\n";
109   int status = proc.Communicate(&in, nullptr, nullptr);
110   EXPECT_TRUE(WIFEXITED(status));
111   EXPECT_EQ(0, WEXITSTATUS(status));
112 }
113 
TEST_F(SubProcessTest,StdinStdout)114 TEST_F(SubProcessTest, StdinStdout) {
115   tensorflow::SubProcess proc;
116   proc.SetProgram("/usr/bin/wc", {"wc", "-l"});
117   proc.SetChannelAction(CHAN_STDIN, ACTION_PIPE);
118   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
119   EXPECT_TRUE(proc.Start());
120 
121   string in = "foobar\nbarfoo\nhaha\n";
122   string out;
123   int status = proc.Communicate(&in, &out, nullptr);
124   EXPECT_TRUE(WIFEXITED(status));
125   EXPECT_EQ(0, WEXITSTATUS(status));
126   int count = stoi(out);
127   EXPECT_EQ(3, count);
128 }
129 
TEST_F(SubProcessTest,StdinChildExit)130 TEST_F(SubProcessTest, StdinChildExit) {
131   tensorflow::SubProcess proc;
132   proc.SetProgram("/bin/sleep", {"sleep", "0"});
133   proc.SetChannelAction(CHAN_STDIN, ACTION_PIPE);
134   EXPECT_TRUE(proc.Start());
135 
136   // Verify that the parent handles the child exiting immediately as the
137   // parent is trying to write a large string to the child's stdin.
138   string in;
139   in.reserve(1000000);
140   for (int i = 0; i < 100000; i++) {
141     in += "hello xyz\n";
142   }
143 
144   int status = proc.Communicate(&in, nullptr, nullptr);
145   EXPECT_TRUE(WIFEXITED(status));
146   EXPECT_EQ(0, WEXITSTATUS(status));
147 }
148 
TEST_F(SubProcessTest,StdinStdoutOverlap)149 TEST_F(SubProcessTest, StdinStdoutOverlap) {
150   tensorflow::SubProcess proc;
151   proc.SetProgram("/bin/cat", {"cat"});
152   proc.SetChannelAction(CHAN_STDIN, ACTION_PIPE);
153   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
154   EXPECT_TRUE(proc.Start());
155 
156   // Verify that the parent handles multiplexed reading/writing to the child
157   // process.  The string is large enough to exceed the buffering of the pipes.
158   string in;
159   in.reserve(1000000);
160   for (int i = 0; i < 100000; i++) {
161     in += "hello xyz\n";
162   }
163 
164   string out;
165   int status = proc.Communicate(&in, &out, nullptr);
166   EXPECT_TRUE(WIFEXITED(status));
167   EXPECT_EQ(0, WEXITSTATUS(status));
168   EXPECT_EQ(in, out);
169 }
170 
TEST_F(SubProcessTest,KillProc)171 TEST_F(SubProcessTest, KillProc) {
172   tensorflow::SubProcess proc;
173   proc.SetProgram("/bin/cat", {"cat"});
174   proc.SetChannelAction(CHAN_STDIN, ACTION_PIPE);
175   proc.SetChannelAction(CHAN_STDOUT, ACTION_PIPE);
176   EXPECT_TRUE(proc.Start());
177 
178   EXPECT_TRUE(proc.Kill(SIGKILL));
179   EXPECT_TRUE(proc.Wait());
180 
181   EXPECT_FALSE(proc.Kill(SIGKILL));
182 }
183 
184 }  // namespace tensorflow
185