]> git.localhorst.tv Git - blank.git/blob - tst/integration/TestInstance.cpp
simple test for client
[blank.git] / tst / integration / TestInstance.cpp
1 #include "TestInstance.hpp"
2
3 #include <cppunit/extensions/HelperMacros.h>
4
5 using namespace std;
6
7
8 namespace blank {
9 namespace test {
10
11 namespace {
12
13 Process::Arguments combine_args(const TempDir &dir, const Process::Arguments &in, bool cmd) {
14         Process::Arguments out;
15         out.reserve(in.size() + (cmd ? 5 : 3));
16         out.emplace_back("blank");
17         out.insert(out.end(), in.begin(), in.end());
18         out.emplace_back("--save-path");
19         out.emplace_back(dir.Path());
20         if (cmd) {
21                 out.emplace_back("--cmd-port");
22                 out.emplace_back("12354");
23         }
24         return out;
25 }
26
27 }
28
29 TestInstance::TestInstance(const Process::Arguments &args, bool cmd)
30 : dir()
31 , proc("./blank" BLANK_SUFFIX, combine_args(dir, args, cmd))
32 , conn()
33 , out_buf()
34 , err_buf()
35 , cmd_buf()
36 , name("blank" BLANK_SUFFIX) {
37         if (cmd) {
38                 // wait for command service startup
39                 WaitOutputLine("listening on TCP port 12354");
40                 // connect to command service
41                 conn = tcp::Socket("localhost", 12354);
42         }
43         for (const auto &arg : args) {
44                 name += ' ';
45                 name += arg;
46         }
47 }
48
49 TestInstance::~TestInstance() {
50         proc.Terminate();
51 }
52
53
54 void TestInstance::WriteInput(const string &data) {
55         AssertRunning();
56         const char *i = data.c_str();
57         const char *end = i + data.length();
58         while (i != end) {
59                 size_t len = proc.WriteIn(i, end - i);
60                 if (len == 0) {
61                         throw runtime_error("failed write to stdin of " + name);
62                 }
63                 i += len;
64         }
65 }
66
67 void TestInstance::ReadOutputLine(string &line) {
68         while (!out_buf.Extract(line)) {
69                 // buffer exhausted, fetch more data
70                 int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 5000);
71                 if (len == 0) {
72                         throw runtime_error("failed read from stdout of " + name);
73                 }
74                 out_buf.Update(len);
75         }
76 }
77
78 void TestInstance::AssertOutputLine(const string &expected) {
79         string line;
80         if (past_out.empty()) {
81                 ReadOutputLine(line);
82         } else {
83                 line = past_out.front();
84                 past_out.pop_front();
85         }
86         CPPUNIT_ASSERT_EQUAL_MESSAGE(
87                 "unexpected line in stdout of " + name,
88                 expected, line);
89 }
90
91 void TestInstance::WaitOutputLine(const string &expected) {
92         for (list<string>::iterator i(past_out.begin()); i != past_out.end(); ++i) {
93                 if (*i == expected) {
94                         past_out.erase(i);
95                         return;
96                 }
97         }
98         string line;
99         while (true) {
100                 ReadOutputLine(line);
101                 if (line == expected) {
102                         return;
103                 } else {
104                         past_out.push_back(line);
105                 }
106         }
107 }
108
109 void TestInstance::ExhaustOutput(string &output) {
110         output.clear();
111         for (const auto &line : past_out) {
112                 output += line;
113                 output += '\n';
114         }
115         past_out.clear();
116         string line;
117         while (true) {
118                 if (out_buf.Extract(line)) {
119                         output += line;
120                         output += '\n';
121                 } else {
122                         // buffer exhausted, fetch more data
123                         int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 5000);
124                         if (len == 0) {
125                                 // eof
126                                 return;
127                         }
128                         out_buf.Update(len);
129                 }
130         }
131 }
132
133 void TestInstance::AssertNoOutput() {
134         string output;
135         ExhaustOutput(output);
136         CPPUNIT_ASSERT_EQUAL_MESSAGE(
137                 "unexpected output of test instance " + name,
138                 string(""), output);
139 }
140
141
142 void TestInstance::ReadErrorLine(string &line) {
143         while (!err_buf.Extract(line)) {
144                 // buffer exhausted, fetch more data
145                 int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 5000);
146                 if (len == 0) {
147                         throw runtime_error("failed read from stderr of " + name);
148                 }
149                 err_buf.Update(len);
150         }
151 }
152
153 void TestInstance::AssertErrorLine(const string &expected) {
154         string line;
155         if (past_err.empty()) {
156                 ReadErrorLine(line);
157         } else {
158                 line = past_err.front();
159                 past_err.pop_front();
160         }
161         CPPUNIT_ASSERT_EQUAL_MESSAGE(
162                 "unexpected line in stderr",
163                 expected, line);
164 }
165
166 void TestInstance::WaitErrorLine(const string &expected) {
167         for (list<string>::iterator i(past_err.begin()); i != past_err.end(); ++i) {
168                 if (*i == expected) {
169                         past_err.erase(i);
170                         return;
171                 }
172         }
173         string line;
174         while (true) {
175                 ReadErrorLine(line);
176                 if (line == expected) {
177                         return;
178                 } else {
179                         past_err.push_back(line);
180                 }
181         }
182 }
183
184 void TestInstance::ExhaustError(string &error) {
185         error.clear();
186         for (const auto &line : past_err) {
187                 error += line;
188                 error += '\n';
189         }
190         past_err.clear();
191         string line;
192         while (true) {
193                 if (err_buf.Extract(line)) {
194                         error += line;
195                         error += '\n';
196                 } else {
197                         // buffer exhausted, fetch more data
198                         int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 5000);
199                         if (len == 0) {
200                                 // eof
201                                 return;
202                         }
203                         err_buf.Update(len);
204                 }
205         }
206 }
207
208 void TestInstance::AssertNoError() {
209         string error;
210         ExhaustError(error);
211         CPPUNIT_ASSERT_EQUAL_MESSAGE(
212                 "unexpected error output of test instance " + name,
213                 string(""), error);
214 }
215
216
217 void TestInstance::Terminate() {
218         if (!proc.Terminated()) {
219                 proc.Terminate();
220         }
221 }
222
223 void TestInstance::AssertRunning() {
224         CPPUNIT_ASSERT_MESSAGE(
225                 "test instance " + name + " terminated unexpectedly",
226                 !proc.Terminated());
227 }
228
229 void TestInstance::AssertTerminated() {
230         CPPUNIT_ASSERT_MESSAGE(
231                 "test instance " + name + " did not terminate as expected",
232                 proc.Terminated());
233 }
234
235 void TestInstance::AssertExitStatus(int expected) {
236         CPPUNIT_ASSERT_EQUAL_MESSAGE(
237                 "unexpected exit status from child program " + name,
238                 expected, proc.Join());
239 }
240
241
242 void TestInstance::WaitCommandMessage(const string &line) {
243         WaitCommandLine(" > " + line);
244 }
245
246 void TestInstance::WaitCommandError(const string &line) {
247         WaitCommandLine(" ! " + line);
248 }
249
250 void TestInstance::WaitCommandBroadcast(const string &line) {
251         WaitCommandLine(" @ " + line);
252 }
253
254 void TestInstance::WaitCommandLine(const string &expected) {
255         string line;
256         while (true) {
257                 if (!cmd_buf.Extract(line)) {
258                         // buffer exhausted, fetch more data
259                         cmd_buf.Update(conn.Recv(cmd_buf.WriteHead(), cmd_buf.Remain()));
260                         continue;
261                 }
262                 if (line == expected) {
263                         return;
264                 }
265         }
266 }
267
268 }
269 }