summaryrefslogtreecommitdiffstats
path: root/chrome/browser/diagnostics
diff options
context:
space:
mode:
authorcpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-03 03:56:22 +0000
committercpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-03 03:56:22 +0000
commit47dc7a0b28e8ee8c7fe1f47318234be9b017f4aa (patch)
tree2f32800b4f027020a17c068dd279bb011e7e7617 /chrome/browser/diagnostics
parent187a031308c1ffcc8eb6f9d1392332be3e246b78 (diff)
downloadchromium_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.cc220
-rw-r--r--chrome/browser/diagnostics/diagnostics_main.h6
-rw-r--r--chrome/browser/diagnostics/diagnostics_model.cc14
-rw-r--r--chrome/browser/diagnostics/diagnostics_model_unittest.cc7
-rw-r--r--chrome/browser/diagnostics/diagnostics_test.h4
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() {