diff options
author | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-03 03:56:22 +0000 |
---|---|---|
committer | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-03 03:56:22 +0000 |
commit | 47dc7a0b28e8ee8c7fe1f47318234be9b017f4aa (patch) | |
tree | 2f32800b4f027020a17c068dd279bb011e7e7617 /chrome/browser/diagnostics | |
parent | 187a031308c1ffcc8eb6f9d1392332be3e246b78 (diff) | |
download | chromium_src-47dc7a0b28e8ee8c7fe1f47318234be9b017f4aa.zip chromium_src-47dc7a0b28e8ee8c7fe1f47318234be9b017f4aa.tar.gz chromium_src-47dc7a0b28e8ee8c7fe1f47318234be9b017f4aa.tar.bz2 |
Basic console output for diagnostics mode windows-only
Also Wires --diagnostics to the diagnostics entry point
start chrome with --diagnostics and watch pretty output
BUG=27885
TEST= unit tests included
Review URL: http://codereview.chromium.org/454020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33663 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/diagnostics')
-rw-r--r-- | chrome/browser/diagnostics/diagnostics_main.cc | 220 | ||||
-rw-r--r-- | chrome/browser/diagnostics/diagnostics_main.h | 6 | ||||
-rw-r--r-- | chrome/browser/diagnostics/diagnostics_model.cc | 14 | ||||
-rw-r--r-- | chrome/browser/diagnostics/diagnostics_model_unittest.cc | 7 | ||||
-rw-r--r-- | chrome/browser/diagnostics/diagnostics_test.h | 4 |
5 files changed, 244 insertions, 7 deletions
diff --git a/chrome/browser/diagnostics/diagnostics_main.cc b/chrome/browser/diagnostics/diagnostics_main.cc index e7ba314..59a3814 100644 --- a/chrome/browser/diagnostics/diagnostics_main.cc +++ b/chrome/browser/diagnostics/diagnostics_main.cc @@ -3,3 +3,223 @@ // found in the LICENSE file. #include "chrome/browser/diagnostics/diagnostics_main.h" + +#include "app/app_paths.h" +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/string_util.h" +#include "chrome/browser/diagnostics/diagnostics_model.h" +#include "chrome/common/chrome_paths.h" + +#if defined(OS_WIN) +#include "base/win_util.h" + +namespace { +// This is a minimalistic class to wrap the windows console operating +// in high-level IO mode. This will be eventually replaced by a view +// that can be subclassed for each platform and that the approved look +// and feel. +class SimpleConsole { + public: + // The ctor allocates a console always. This avoids having to ask + // the user to start chrome from a command prompt. + SimpleConsole() + : std_out_(INVALID_HANDLE_VALUE), + std_in_(INVALID_HANDLE_VALUE) { + } + + ~SimpleConsole() { + ::FreeConsole(); + } + // Init must be called before using any other method. If it returns + // false there would be no console output. + bool Init() { + ::AllocConsole(); + return SetIOHandles(); + } + + // Writes a string to the console with the current color. + bool Write(const std::wstring& txt) { + DWORD sz = txt.size(); + return (TRUE == ::WriteConsoleW(std_out_, txt.c_str(), sz, &sz, NULL)); + } + + // Reads a string from the console. Internally it is limited to 256 + // characters. + bool Read(std::wstring* txt) { + wchar_t buf[256]; + DWORD read = sizeof(buf) - sizeof(buf[0]); + if (!::ReadConsoleW(std_in_, buf, read, &read, NULL)) + return false; + // Note that |read| is in bytes. + txt->assign(buf, read/2); + return true; + } + + // Sets the foreground and backgroudn color. See |kRedFG| or |kGreenFG| + // below for examples how to combine colors. + bool SetColor(uint16 color_combo) { + return (TRUE == ::SetConsoleTextAttribute(std_out_, color_combo)); + } + + private: + bool SetIOHandles() { + std_out_ = ::GetStdHandle(STD_OUTPUT_HANDLE); + std_in_ = ::GetStdHandle(STD_INPUT_HANDLE); + return ((std_out_ != INVALID_HANDLE_VALUE) && + (std_in_ != INVALID_HANDLE_VALUE)); + } + + // The input and output handles to the screen. They seem to be + // implemented as pipes but they have non-documented protocol. + HANDLE std_out_; + HANDLE std_in_; + + DISALLOW_COPY_AND_ASSIGN(SimpleConsole); +}; + +// This class wraps a SimpleConsole for the specific use case of +// writing the results of the diagnostic tests. +// TODO(cpu) figure out the localization strategy. +class TestWriter { + public: + // The |console| must be valid and properly initialized. This + // class does not own it. + explicit TestWriter(SimpleConsole* console) : console_(console) { + } + + // Write an informational line of text in white over black. + bool WriteInfoText(const std::wstring& txt) { + console_->SetColor(kWhiteFG); + return console_->Write(txt); + } + + // Write a result block. It consist of two lines. The first line + // has [PASS] or [FAIL] with |name| and the second line has + // the text in |extra|. + bool WriteResult(bool success, const std::wstring& name, + const std::wstring& extra) { + if (success) { + console_->SetColor(kGreenFG); + console_->Write(L"[PASS] "); + } else { + console_->SetColor(kRedFG); + console_->Write(L"[FAIL] "); + } + WriteInfoText(name + L"\n"); + std::wstring second_line(L" "); + second_line.append(extra); + return WriteInfoText(second_line + L"\n\n"); + } + + private: + // constants for the colors we use. + static const uint16 kRedFG = FOREGROUND_RED|FOREGROUND_INTENSITY; + static const uint16 kGreenFG = FOREGROUND_GREEN|FOREGROUND_INTENSITY; + static const uint16 kWhiteFG = kRedFG | kGreenFG | FOREGROUND_BLUE; + + SimpleConsole* console_; + + DISALLOW_COPY_AND_ASSIGN(TestWriter); +}; + +// This class is a basic test controller. In this design the view (TestWriter) +// and the model (DiagnosticsModel) do not talk to each other directly but they +// are mediated by the controller. This has a name: 'passive view'. +// More info at http://martinfowler.com/eaaDev/PassiveScreen.html +class TestController : public DiagnosticsModel::Observer { + public: + explicit TestController(TestWriter* writer) : writer_(writer) { + } + + // Run all the diagnostics of |model| and invoke the view as the model + // callbacks arrive. + void Run(DiagnosticsModel* model) { + writer_->WriteInfoText(L"Chrome Diagnostics\n"); + if (!model) { + writer_->WriteResult(false, L"Diagnostics start", L"model is null"); + return; + } + int count = model->GetTestAvailableCount(); + writer_->WriteInfoText(StringPrintf(L"%d available test(s)\n\n", count)); + model->RunAll(this); + } + + // Next four are overriden from DiagnosticsModel::Observer + virtual void OnProgress(int id, int percent, DiagnosticsModel* model) { + } + + virtual void OnSkipped(int id, DiagnosticsModel* model) { + // TODO(cpu): display skipped tests. + } + + virtual void OnFinished(int id, DiagnosticsModel* model) { + // As each test completes we output the results. + ShowResult(model->GetTest(id)); + } + + virtual void OnDoneAll(DiagnosticsModel* model) { + writer_->WriteInfoText(L"DONE\n\n"); + } + + private: + void ShowResult(DiagnosticsModel::TestInfo& test_info) { + bool success = (DiagnosticsModel::TEST_OK == test_info.GetResult()); + writer_->WriteResult(success, test_info.GetTitle(), + test_info.GetAdditionalInfo()); + } + + DiagnosticsModel* model_; + TestWriter* writer_; + + DISALLOW_COPY_AND_ASSIGN(TestController); +}; + +} + +// This entry point is called from ChromeMain() when very few things +// have been initialized. To wit: +// -(win) Breakpad +// -(macOS) base::EnableTerminationOnHeapCorruption() +// -(macOS) base::EnableTerminationOnOutOfMemory() +// -(all) RegisterInvalidParamHandler() +// -(all) base::AtExitManager::AtExitManager() +// -(macOS) base::ScopedNSAutoreleasePool +// -(posix) Singleton<base::GlobalDescriptors>::Set(kPrimaryIPCChannel) +// -(linux) Singleton<base::GlobalDescriptors>::Set(kCrashDumpSignal) +// -(posix) setlocale(LC_ALL,..) +// -(all) CommandLine::Init(); + +int DiagnosticsMain(const CommandLine& command_line) { + // If we can't initialize the console exit right away. + SimpleConsole console; + if (!console.Init()) + return 1; + + // We need to have the path providers registered. They both + // return void so there is no early error signal that we can use. + app::RegisterPathProvider(); + chrome::RegisterPathProvider(); + + TestWriter writer(&console); + DiagnosticsModel* model = MakeDiagnosticsModel(); + TestController controller(&writer); + + // Run all the diagnostic tests. + controller.Run(model); + delete model; + + // Block here so the user can see the results. + writer.WriteInfoText(L"Press [enter] to continue\n"); + std::wstring txt; + console.Read(&txt); + return 0; +} + +#else // defined(OS_WIN) + +int DiagnosticsMain(const CommandLine& command_line) { + return 0; +} + +#endif diff --git a/chrome/browser/diagnostics/diagnostics_main.h b/chrome/browser/diagnostics/diagnostics_main.h index 4153925..0ce1404 100644 --- a/chrome/browser/diagnostics/diagnostics_main.h +++ b/chrome/browser/diagnostics/diagnostics_main.h @@ -5,5 +5,11 @@ #ifndef CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_ #define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_ +class CommandLine; + +// Entry point for the diagnostics mode. Most of the initialization that you +// can see in ChromeMain() will be repeated here or will be done differently. +int DiagnosticsMain(const CommandLine& command_line); + #endif // CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_ diff --git a/chrome/browser/diagnostics/diagnostics_model.cc b/chrome/browser/diagnostics/diagnostics_model.cc index 82168e0..dc6b35a 100644 --- a/chrome/browser/diagnostics/diagnostics_model.cc +++ b/chrome/browser/diagnostics/diagnostics_model.cc @@ -77,23 +77,27 @@ class DiagnosticsModelImpl : public DiagnosticsModel { // TODO(cpu): Localize strings. class UserPathsTest : public DiagnosticTest { public: - UserPathsTest() : DiagnosticTest(ASCIIToUTF16("User Directory")) {} + UserPathsTest() : DiagnosticTest(ASCIIToUTF16("User data Directory")) {} // Not used at the moment but it allows one test to query the status // of another test so we can build test dependencies. virtual int GetId() { return 0; } virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) { - FilePath data_dir; - if (!PathService::Get(chrome::DIR_USER_DATA, &data_dir)) { + FilePath dir; + if (!PathService::Get(chrome::DIR_USER_DATA, &dir)) { RecordStopFailure(ASCIIToUTF16("Path provider failure")); return false; } - if (!file_util::PathExists(data_dir)) { + if (!file_util::PathExists(dir)) { RecordFailure(ASCIIToUTF16("No user data dir found")); return true; } - RecordSuccess(ASCIIToUTF16("Directory found")); + if (!file_util::PathIsWritable(dir)) { + RecordFailure(ASCIIToUTF16("User data dir is not writable")); + return true; + } + RecordSuccess(ASCIIToUTF16("Directory exists and is writable")); return true; } diff --git a/chrome/browser/diagnostics/diagnostics_model_unittest.cc b/chrome/browser/diagnostics/diagnostics_model_unittest.cc index f6a7697..442db84 100644 --- a/chrome/browser/diagnostics/diagnostics_model_unittest.cc +++ b/chrome/browser/diagnostics/diagnostics_model_unittest.cc @@ -27,7 +27,7 @@ class DiagnosticsModelTest : public testing::Test { // The test observer is used to know if the callbacks are being called. class UTObserver: public DiagnosticsModel::Observer { public: - UTObserver() : done_(false), progress_called_(0) {} + UTObserver() : done_(false), progress_called_(0), finished_(0) {} virtual void OnProgress(int id, int percent, DiagnosticsModel* model) { EXPECT_TRUE(model != NULL); @@ -40,6 +40,7 @@ class UTObserver: public DiagnosticsModel::Observer { virtual void OnFinished(int id, DiagnosticsModel* model) { EXPECT_TRUE(model != NULL); + ++finished_; } virtual void OnDoneAll(DiagnosticsModel* model) { @@ -51,9 +52,12 @@ class UTObserver: public DiagnosticsModel::Observer { int progress_called() const { return progress_called_; } + int finished() const { return finished_;} + private: bool done_; int progress_called_; + int finished_; }; // Test that the initial state is correct. We only have one test @@ -73,4 +77,5 @@ TEST_F(DiagnosticsModelTest, RunAll) { EXPECT_TRUE(observer.done()); EXPECT_GT(observer.progress_called(), 0); EXPECT_EQ(1, model_->GetTestRunCount()); + EXPECT_EQ(1, observer.finished()); } diff --git a/chrome/browser/diagnostics/diagnostics_test.h b/chrome/browser/diagnostics/diagnostics_test.h index 8d12bc5..c6b6924 100644 --- a/chrome/browser/diagnostics/diagnostics_test.h +++ b/chrome/browser/diagnostics/diagnostics_test.h @@ -32,7 +32,9 @@ class DiagnosticTest : public DiagnosticsModel::TestInfo { bool Execute(DiagnosticsModel::Observer* observer, DiagnosticsModel* model) { result_ = DiagnosticsModel::TEST_RUNNING; observer->OnProgress(GetId(), 0, model); - return ExecuteImpl(observer); + bool keep_going = ExecuteImpl(observer); + observer->OnFinished(GetId(), model); + return keep_going; } virtual string16 GetTitle() { |