Home | History | Annotate | Download | only in process_proxy
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <gtest/gtest.h>
      6 
      7 #include <queue>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/callback.h"
     13 #include "base/files/file_util.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/posix/eintr_wrapper.h"
     16 #include "base/run_loop.h"
     17 #include "base/strings/string_util.h"
     18 #include "base/threading/thread.h"
     19 #include "chromeos/process_proxy/process_output_watcher.h"
     20 
     21 namespace chromeos {
     22 
     23 struct TestCase {
     24   TestCase(const std::string& input, bool send_terminating_null)
     25       : input(input),
     26         should_send_terminating_null(send_terminating_null),
     27         expected_output(input) {}
     28 
     29   // Conctructor for cases where the output is not expected to be the same as
     30   // input.
     31   TestCase(const std::string& input,
     32            bool send_terminating_null,
     33            const std::string& expected_output)
     34       : input(input),
     35         should_send_terminating_null(send_terminating_null),
     36         expected_output(expected_output) {}
     37 
     38   std::string input;
     39   bool should_send_terminating_null;
     40   std::string expected_output;
     41 };
     42 
     43 class ProcessWatcherExpectations {
     44  public:
     45   ProcessWatcherExpectations() {}
     46 
     47   void SetTestCase(const TestCase& test_case) {
     48     received_from_out_ = 0;
     49 
     50     out_expectations_ = test_case.expected_output;
     51     if (test_case.should_send_terminating_null)
     52       out_expectations_.append(std::string("", 1));
     53   }
     54 
     55   bool CheckExpectations(const std::string& data, ProcessOutputType type) {
     56     EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type);
     57     if (type != PROCESS_OUTPUT_TYPE_OUT)
     58       return false;
     59 
     60     if (out_expectations_.length() == 0 && data.length() == 0)
     61       return true;
     62 
     63     EXPECT_LT(received_from_out_, out_expectations_.length());
     64     if (received_from_out_ >= out_expectations_.length())
     65       return false;
     66 
     67     EXPECT_EQ(received_from_out_,
     68               out_expectations_.find(data, received_from_out_));
     69     if (received_from_out_ != out_expectations_.find(data, received_from_out_))
     70       return false;
     71 
     72     received_from_out_ += data.length();
     73     return true;
     74   }
     75 
     76   bool IsDone() {
     77     return received_from_out_ >= out_expectations_.length();
     78   }
     79 
     80  private:
     81   std::string out_expectations_;
     82   size_t received_from_out_;
     83 };
     84 
     85 class ProcessOutputWatcherTest : public testing::Test {
     86  public:
     87   ProcessOutputWatcherTest() : output_watch_thread_started_(false),
     88                                failed_(false) {
     89   }
     90 
     91   virtual ~ProcessOutputWatcherTest() {}
     92 
     93   virtual void TearDown() OVERRIDE {
     94     if (output_watch_thread_started_)
     95       output_watch_thread_->Stop();
     96   }
     97 
     98   void StartWatch(int pt, int stop) {
     99     // This will delete itself.
    100     ProcessOutputWatcher* crosh_watcher = new ProcessOutputWatcher(pt, stop,
    101         base::Bind(&ProcessOutputWatcherTest::OnRead, base::Unretained(this)));
    102     crosh_watcher->Start();
    103   }
    104 
    105   void OnRead(ProcessOutputType type, const std::string& output) {
    106     ASSERT_FALSE(failed_);
    107     failed_ = !expectations_.CheckExpectations(output, type);
    108     if (failed_ || expectations_.IsDone()) {
    109       ASSERT_FALSE(test_case_done_callback_.is_null());
    110       message_loop_.PostTask(FROM_HERE, test_case_done_callback_);
    111       test_case_done_callback_.Reset();
    112     }
    113   }
    114 
    115  protected:
    116   std::string VeryLongString() {
    117     std::string result = "0123456789";
    118     for (int i = 0; i < 8; i++)
    119       result = result.append(result);
    120     return result;
    121   }
    122 
    123   void RunTest(const std::vector<TestCase>& test_cases) {
    124     ASSERT_FALSE(output_watch_thread_started_);
    125     output_watch_thread_.reset(new base::Thread("ProcessOutpuWatchThread"));
    126     output_watch_thread_started_ = output_watch_thread_->Start();
    127     ASSERT_TRUE(output_watch_thread_started_);
    128 
    129     int pt_pipe[2], stop_pipe[2];
    130     ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
    131     ASSERT_FALSE(HANDLE_EINTR(pipe(stop_pipe)));
    132 
    133     output_watch_thread_->message_loop()->PostTask(
    134         FROM_HERE,
    135         base::Bind(&ProcessOutputWatcherTest::StartWatch,
    136                    base::Unretained(this),
    137                    pt_pipe[0],
    138                    stop_pipe[0]));
    139 
    140     for (size_t i = 0; i < test_cases.size(); i++) {
    141       expectations_.SetTestCase(test_cases[i]);
    142 
    143       base::RunLoop run_loop;
    144       ASSERT_TRUE(test_case_done_callback_.is_null());
    145       test_case_done_callback_ = run_loop.QuitClosure();
    146 
    147       const std::string& test_str = test_cases[i].input;
    148       // Let's make inputs not NULL terminated, unless other is specified in
    149       // the test case.
    150       ssize_t test_size = test_str.length() * sizeof(*test_str.c_str());
    151       if (test_cases[i].should_send_terminating_null)
    152         test_size += sizeof(*test_str.c_str());
    153       EXPECT_EQ(test_size,
    154                 base::WriteFileDescriptor(pt_pipe[1], test_str.c_str(),
    155                                           test_size));
    156 
    157       run_loop.Run();
    158       EXPECT_TRUE(expectations_.IsDone());
    159       if (failed_)
    160         break;
    161     }
    162 
    163     // Send stop signal. It is not important which string we send.
    164     EXPECT_EQ(1, base::WriteFileDescriptor(stop_pipe[1], "q", 1));
    165 
    166     EXPECT_NE(-1, IGNORE_EINTR(close(stop_pipe[1])));
    167     EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1])));
    168   }
    169 
    170  private:
    171   base::Closure test_case_done_callback_;
    172   base::MessageLoop message_loop_;
    173   scoped_ptr<base::Thread> output_watch_thread_;
    174   bool output_watch_thread_started_;
    175   bool failed_;
    176   ProcessWatcherExpectations expectations_;
    177   std::vector<TestCase> exp;
    178 };
    179 
    180 // http://crbug.com/396496
    181 TEST_F(ProcessOutputWatcherTest, DISABLED_OutputWatcher) {
    182   std::vector<TestCase> test_cases;
    183   test_cases.push_back(TestCase("t", false));
    184   test_cases.push_back(TestCase("testing output\n", false));
    185   test_cases.push_back(TestCase("testing error\n", false));
    186   test_cases.push_back(TestCase("testing error1\n", false));
    187   test_cases.push_back(TestCase("testing output1\n", false));
    188   test_cases.push_back(TestCase("testing output2\n", false));
    189   test_cases.push_back(TestCase("testing output3\n", false));
    190   test_cases.push_back(TestCase(VeryLongString(), false));
    191   test_cases.push_back(TestCase("testing error2\n", false));
    192 
    193   RunTest(test_cases);
    194 }
    195 
    196 // http://crbug.com/396496
    197 TEST_F(ProcessOutputWatcherTest, DISABLED_SplitUTF8Character) {
    198   std::vector<TestCase> test_cases;
    199   test_cases.push_back(TestCase("test1\xc2", false, "test1"));
    200   test_cases.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
    201 
    202   RunTest(test_cases);
    203 }
    204 
    205 // http://crbug.com/396496
    206 TEST_F(ProcessOutputWatcherTest, DISABLED_SplitSoleUTF8Character) {
    207   std::vector<TestCase> test_cases;
    208   test_cases.push_back(TestCase("\xc2", false, ""));
    209   test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
    210 
    211   RunTest(test_cases);
    212 }
    213 
    214 // http://crbug.com/396496
    215 TEST_F(ProcessOutputWatcherTest, DISABLED_SplitUTF8CharacterLength3) {
    216   std::vector<TestCase> test_cases;
    217   test_cases.push_back(TestCase("test3\xe2\x82", false, "test3"));
    218   test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
    219 
    220   RunTest(test_cases);
    221 }
    222 
    223 // http://crbug.com/396496
    224 TEST_F(ProcessOutputWatcherTest, DISABLED_SplitSoleUTF8CharacterThreeWays) {
    225   std::vector<TestCase> test_cases;
    226   test_cases.push_back(TestCase("\xe2", false, ""));
    227   test_cases.push_back(TestCase("\x82", false, ""));
    228   test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
    229 
    230   RunTest(test_cases);
    231 }
    232 
    233 TEST_F(ProcessOutputWatcherTest, EndsWithThreeByteUTF8Character) {
    234   std::vector<TestCase> test_cases;
    235   test_cases.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
    236 
    237   RunTest(test_cases);
    238 }
    239 
    240 TEST_F(ProcessOutputWatcherTest, SoleThreeByteUTF8Character) {
    241   std::vector<TestCase> test_cases;
    242   test_cases.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
    243 
    244   RunTest(test_cases);
    245 }
    246 
    247 TEST_F(ProcessOutputWatcherTest, HasThreeByteUTF8Character) {
    248   std::vector<TestCase> test_cases;
    249   test_cases.push_back(
    250       TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
    251 
    252   RunTest(test_cases);
    253 }
    254 
    255 TEST_F(ProcessOutputWatcherTest, MulitByteUTF8CharNullTerminated) {
    256   std::vector<TestCase> test_cases;
    257   test_cases.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
    258 
    259   RunTest(test_cases);
    260 }
    261 
    262 // http://crbug.com/396496
    263 TEST_F(ProcessOutputWatcherTest, DISABLED_MultipleMultiByteUTF8Characters) {
    264   std::vector<TestCase> test_cases;
    265   test_cases.push_back(
    266       TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
    267   test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
    268 
    269   RunTest(test_cases);
    270 }
    271 
    272 TEST_F(ProcessOutputWatcherTest, ContainsInvalidUTF8) {
    273   std::vector<TestCase> test_cases;
    274   test_cases.push_back(TestCase("\xc2_", false, "\xc2_"));
    275 
    276   RunTest(test_cases);
    277 }
    278 
    279 // http://crbug.com/396496
    280 TEST_F(ProcessOutputWatcherTest, DISABLED_InvalidUTF8SeriesOfTrailingBytes) {
    281   std::vector<TestCase> test_cases;
    282   test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
    283   test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
    284 
    285   RunTest(test_cases);
    286 }
    287 
    288 TEST_F(ProcessOutputWatcherTest, EndsWithInvalidUTF8) {
    289   std::vector<TestCase> test_cases;
    290   test_cases.push_back(TestCase("\xff", false, "\xff"));
    291 
    292   RunTest(test_cases);
    293 }
    294 
    295 // http://crbug.com/396496
    296 TEST_F(ProcessOutputWatcherTest, DISABLED_FourByteUTF8) {
    297   std::vector<TestCase> test_cases;
    298   test_cases.push_back(TestCase("\xf0\xa4\xad", false, ""));
    299   test_cases.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
    300 
    301   RunTest(test_cases);
    302 }
    303 
    304 // Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
    305 // not terminate output watcher.
    306 // http://crbug.com/396496
    307 TEST_F(ProcessOutputWatcherTest, DISABLED_SendNull) {
    308   std::vector<TestCase> test_cases;
    309   // This will send '\0' to output watcher.
    310   test_cases.push_back(TestCase("", true));
    311   // Let's verify that next input also gets detected (i.e. output watcher does
    312   // not exit after seeing '\0' from previous test case).
    313   test_cases.push_back(TestCase("a", true));
    314 
    315   RunTest(test_cases);
    316 }
    317 
    318 }  // namespace chromeos
    319