1 : // Copyright 2012 Google Inc. 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 : #include "syzygy/trace/logger/logger_app.h"
16 :
17 : #include <psapi.h>
18 : #include <userenv.h>
19 :
20 : #include "base/command_line.h"
21 : #include "base/environment.h"
22 : #include "base/file_util.h"
23 : #include "base/process_util.h"
24 : #include "base/scoped_temp_dir.h"
25 : #include "base/string_util.h"
26 : #include "base/stringprintf.h"
27 : #include "base/utf_string_conversions.h"
28 : #include "base/memory/scoped_ptr.h"
29 : #include "gmock/gmock.h"
30 : #include "gtest/gtest.h"
31 : #include "syzygy/common/align.h"
32 : #include "syzygy/common/unittest_util.h"
33 : #include "syzygy/core/unittest_util.h"
34 : #include "syzygy/trace/client/client_utils.h"
35 : #include "syzygy/trace/parse/parse_utils.h"
36 : #include "syzygy/trace/protocol/call_trace_defs.h"
37 : #include "syzygy/trace/rpc/rpc_helpers.h"
38 : #include "syzygy/trace/service/service_rpc_impl.h"
39 : #include "syzygy/trace/service/trace_file_writer_factory.h"
40 :
41 : using namespace trace::client;
42 :
43 : namespace trace {
44 : namespace logger {
45 :
46 : namespace {
47 :
48 : class TestLoggerApp : public LoggerApp {
49 : public:
50 : using LoggerApp::FindActionHandler;
51 : using LoggerApp::OpenOutputFile;
52 : using LoggerApp::kStart;
53 : using LoggerApp::kSpawn;
54 : using LoggerApp::kStatus;
55 : using LoggerApp::kStop;
56 : using LoggerApp::kInstanceId;
57 : using LoggerApp::kOutputFile;
58 : using LoggerApp::kStdOut;
59 : using LoggerApp::kStdErr;
60 : using LoggerApp::logger_command_line_;
61 : using LoggerApp::app_command_line_;
62 : using LoggerApp::instance_id_;
63 : using LoggerApp::action_;
64 : using LoggerApp::action_handler_;
65 : using LoggerApp::output_file_path_;
66 : using LoggerApp::append_;
67 : };
68 :
69 : typedef common::Application<TestLoggerApp> TestApp;
70 :
71 : class LoggerAppTest : public testing::ApplicationTestBase {
72 : public:
73 : typedef testing::ApplicationTestBase Super;
74 :
75 : LoggerAppTest()
76 : : cmd_line_(FilePath(L"logger.exe")),
77 E : test_impl_(test_app_.implementation()) {
78 E : }
79 :
80 E : void SetUp() {
81 E : Super::SetUp();
82 :
83 : // Several of the tests generate progress and (deliberate) error messages
84 : // that would otherwise clutter the unit-test output.
85 E : logging::SetMinLogLevel(logging::LOG_FATAL);
86 :
87 : // Setup the IO streams.
88 E : CreateTemporaryDir(&temp_dir_);
89 E : stdin_path_ = temp_dir_.Append(L"NUL");
90 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
91 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
92 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
93 :
94 : // Initialize the (potential) input and output path values.
95 E : instance_id_ = base::StringPrintf(L"%d", ::GetCurrentProcessId());
96 E : output_file_path_ = temp_dir_.Append(L"output.txt");
97 :
98 : // Point the application at the test's command-line and IO streams.
99 E : test_app_.set_command_line(&cmd_line_);
100 E : test_app_.set_in(in());
101 E : test_app_.set_out(out());
102 E : test_app_.set_err(err());
103 E : }
104 :
105 : protected:
106 : // Stashes the current log-level before each test instance and restores it
107 : // after each test completes.
108 : testing::ScopedLogLevelSaver log_level_saver;
109 :
110 : // @name The application under test.
111 : // @{
112 : TestApp test_app_;
113 : TestApp::Implementation& test_impl_;
114 : FilePath temp_dir_;
115 : FilePath stdin_path_;
116 : FilePath stdout_path_;
117 : FilePath stderr_path_;
118 : // @}
119 :
120 : // @name Command-line and parameters.
121 : // @{
122 : CommandLine cmd_line_;
123 : std::wstring instance_id_;
124 : FilePath output_file_path_;
125 : // @}
126 : };
127 :
128 : } // namespace
129 :
130 E : TEST_F(LoggerAppTest, GetHelp) {
131 E : cmd_line_.AppendSwitch("help");
132 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
133 E : }
134 :
135 E : TEST_F(LoggerAppTest, EmptyCommandLineFails) {
136 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
137 E : }
138 :
139 E : TEST_F(LoggerAppTest, ParseBasicStart) {
140 : cmd_line_.AppendSwitchPath(
141 E : TestLoggerApp::kOutputFile, output_file_path_);
142 : cmd_line_.AppendSwitchNative(
143 E : TestLoggerApp::kInstanceId, instance_id_);
144 E : cmd_line_.AppendArgNative(TestLoggerApp::kStart);
145 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
146 E : EXPECT_EQ(output_file_path_, test_impl_.output_file_path_);
147 E : EXPECT_EQ(instance_id_, test_impl_.instance_id_);
148 E : EXPECT_EQ(std::wstring(TestLoggerApp::kStart), test_impl_.action_);
149 E : EXPECT_TRUE(test_impl_.app_command_line_.get() == NULL);
150 E : EXPECT_EQ(&TestLoggerApp::Start, test_impl_.action_handler_);
151 E : }
152 :
153 E : TEST_F(LoggerAppTest, ParseStartWithCommand) {
154 E : const FilePath kFooExe(L"foo.exe");
155 E : const std::wstring kSwitchName(L"switch");
156 E : const std::wstring kSwitchValue(L"value");
157 E : const std::wstring kDash(L"--");
158 :
159 : cmd_line_.AppendSwitchPath(
160 E : TestLoggerApp::kOutputFile, output_file_path_);
161 : cmd_line_.AppendSwitchNative(
162 E : TestLoggerApp::kInstanceId, instance_id_);
163 E : cmd_line_.AppendArgNative(TestLoggerApp::kStart);
164 E : cmd_line_.AppendArgNative(kDash);
165 E : cmd_line_.AppendArgNative(kFooExe.value());
166 E : cmd_line_.AppendArgNative(kDash + kSwitchName + L"=" + kSwitchValue);
167 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
168 E : EXPECT_EQ(output_file_path_, test_impl_.output_file_path_);
169 E : EXPECT_EQ(instance_id_, test_impl_.instance_id_);
170 E : EXPECT_EQ(std::wstring(TestLoggerApp::kStart), test_impl_.action_);
171 E : const CommandLine* app_cmd_line = test_impl_.app_command_line_.get();
172 E : ASSERT_TRUE(app_cmd_line != NULL);
173 E : EXPECT_EQ(kFooExe, app_cmd_line->GetProgram());
174 : EXPECT_EQ(kSwitchValue,
175 E : app_cmd_line->GetSwitchValueNative(WideToASCII(kSwitchName)));
176 E : EXPECT_EQ(&TestLoggerApp::Start, test_impl_.action_handler_);
177 E : }
178 :
179 E : TEST_F(LoggerAppTest, ParseSpawn) {
180 : cmd_line_.AppendSwitchNative(
181 E : TestLoggerApp::kInstanceId, instance_id_);
182 E : cmd_line_.AppendArgNative(TestLoggerApp::kSpawn);
183 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
184 E : EXPECT_TRUE(test_impl_.output_file_path_.empty());
185 E : EXPECT_EQ(instance_id_, test_impl_.instance_id_);
186 E : EXPECT_EQ(std::wstring(TestLoggerApp::kSpawn), test_impl_.action_);
187 E : EXPECT_EQ(NULL, test_impl_.app_command_line_.get());
188 E : EXPECT_EQ(&TestLoggerApp::Spawn, test_impl_.action_handler_);
189 E : }
190 :
191 E : TEST_F(LoggerAppTest, ParseStop) {
192 : cmd_line_.AppendSwitchNative(
193 E : TestLoggerApp::kInstanceId, instance_id_);
194 E : cmd_line_.AppendArgNative(TestLoggerApp::kStop);
195 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
196 E : EXPECT_TRUE(test_impl_.output_file_path_.empty());
197 E : EXPECT_EQ(instance_id_, test_impl_.instance_id_);
198 E : EXPECT_EQ(std::wstring(TestLoggerApp::kStop), test_impl_.action_);
199 E : EXPECT_EQ(NULL, test_impl_.app_command_line_.get());
200 E : EXPECT_EQ(&TestLoggerApp::Stop, test_impl_.action_handler_);
201 E : }
202 :
203 E : TEST_F(LoggerAppTest, ParseStatus) {
204 : cmd_line_.AppendSwitchNative(
205 E : TestLoggerApp::kInstanceId, instance_id_);
206 E : cmd_line_.AppendArgNative(TestLoggerApp::kStatus);
207 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
208 E : EXPECT_TRUE(test_impl_.output_file_path_.empty());
209 E : EXPECT_EQ(instance_id_, test_impl_.instance_id_);
210 E : EXPECT_EQ(std::wstring(TestLoggerApp::kStatus), test_impl_.action_);
211 E : EXPECT_EQ(NULL, test_impl_.app_command_line_.get());
212 E : EXPECT_EQ(&TestLoggerApp::Status, test_impl_.action_handler_);
213 E : }
214 :
215 E : TEST_F(LoggerAppTest, ParseUnknown) {
216 E : const std::wstring kUnknown(L"unknown");
217 : cmd_line_.AppendSwitchNative(
218 E : TestLoggerApp::kInstanceId, instance_id_);
219 E : cmd_line_.AppendArgNative(kUnknown);
220 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
221 E : EXPECT_TRUE(test_impl_.output_file_path_.empty());
222 E : EXPECT_EQ(instance_id_, test_impl_.instance_id_);
223 E : EXPECT_EQ(kUnknown, test_impl_.action_);
224 E : EXPECT_EQ(NULL, test_impl_.app_command_line_.get());
225 E : EXPECT_TRUE(test_impl_.action_handler_ == NULL);
226 E : }
227 :
228 E : TEST_F(LoggerAppTest, StartEndToEnd) {
229 : cmd_line_.AppendSwitchNative(
230 E : TestLoggerApp::kInstanceId, instance_id_);
231 E : cmd_line_.AppendArgNative(TestLoggerApp::kStart);
232 E : cmd_line_.AppendArgNative(L"--");
233 E : cmd_line_.AppendArgNative(L"cmd.exe");
234 E : cmd_line_.AppendArgNative(L"/C");
235 E : cmd_line_.AppendArgNative(L"date /t");
236 :
237 E : ASSERT_EQ(0, test_app_.Run());
238 E : }
239 :
240 E : TEST_F(LoggerAppTest, SpawnStatusAndStop) {
241 : // TODO(rogerm): Write me!
242 E : }
243 :
244 : } // namespace logger
245 : } // namespace trace
|