PM: Add EvaluationContext::DumpContext() method.

This generates a JSON-formatted string with all the variables and the
evaluation start-time.

BUG=chromium:355724
TEST=New unit test + Unit tests pass.

Change-Id: Iaa1439b6589b54536aedd59b8f81a58d5c6663ad
Reviewed-on: https://chromium-review.googlesource.com/197548
Reviewed-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: David Zeuthen <zeuthen@chromium.org>
Tested-by: David Zeuthen <zeuthen@chromium.org>
diff --git a/policy_manager/evaluation_context.cc b/policy_manager/evaluation_context.cc
index 03238cf..3a37618 100644
--- a/policy_manager/evaluation_context.cc
+++ b/policy_manager/evaluation_context.cc
@@ -4,12 +4,19 @@
 
 #include "update_engine/policy_manager/evaluation_context.h"
 
+#include <string>
+
 #include <base/bind.h>
+#include <base/json/json_writer.h>
+#include <base/values.h>
+
+#include "update_engine/utils.h"
 
 using base::Closure;
 using base::Time;
 using base::TimeDelta;
 using chromeos_update_engine::ClockInterface;
+using std::string;
 
 namespace chromeos_policy_manager {
 
@@ -134,4 +141,23 @@
   return true;
 }
 
+string EvaluationContext::DumpContext() const {
+  base::DictionaryValue* variables = new base::DictionaryValue();
+  for (auto& it : value_cache_) {
+    variables->SetString(it.first->GetName(), it.second.ToString());
+  }
+
+  base::DictionaryValue value;
+  value.Set("variables", variables);  // Adopts |variables|.
+  value.SetString("evaluation_start",
+                  chromeos_update_engine::utils::ToString(evaluation_start_));
+
+  string json_str;
+  base::JSONWriter::WriteWithOptions(&value,
+                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
+                                     &json_str);
+
+  return json_str;
+}
+
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/evaluation_context.h b/policy_manager/evaluation_context.h
index f894a46..059256e 100644
--- a/policy_manager/evaluation_context.h
+++ b/policy_manager/evaluation_context.h
@@ -85,6 +85,11 @@
   // reseted, removing all the non-const cached values.
   bool RunOnValueChangeOrTimeout(base::Closure callback);
 
+  // Returns a textual representation of the evaluation context,
+  // including the variables and their values. This is intended only
+  // to help with debugging and the format may change in the future.
+  std::string DumpContext() const;
+
  private:
   // Removes all the Observers and timeout callbacks scheduled by
   // RunOnValueChangeOrTimeout(). This method is idempotent.
diff --git a/policy_manager/evaluation_context_unittest.cc b/policy_manager/evaluation_context_unittest.cc
index 0af0251..ccc49c9 100644
--- a/policy_manager/evaluation_context_unittest.cc
+++ b/policy_manager/evaluation_context_unittest.cc
@@ -48,7 +48,8 @@
   virtual void SetUp() {
     // Set the clock to a fixed values.
     fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
-    fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
+    // Mar 2, 2006 1:23:45 UTC is 1141262625 since the Unix Epoch.
+    fake_clock_.SetWallclockTime(Time::FromTimeT(1141262625));
     eval_ctx_ = new EvaluationContext(&fake_clock_);
   }
 
@@ -71,6 +72,7 @@
   // FakeVariables used for testing the EvaluationContext. These are required
   // here to prevent them from going away *before* the EvaluationContext under
   // test does, which keeps a reference to them.
+  FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll};
   FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
   FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
   FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
@@ -304,4 +306,30 @@
   EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
 }
 
+TEST_F(PmEvaluationContextTest, DumpContext) {
+  // |fail_var_| yield "(no value)" since it is unset.
+  eval_ctx_->GetValue(&fail_var_);
+
+  // Check that this is included.
+  fake_int_var_.reset(new int(42));
+  eval_ctx_->GetValue(&fake_int_var_);
+
+  // Check that double-quotes are escaped properly.
+  fake_poll_var_.reset(new string("Hello \"world\"!"));
+  eval_ctx_->GetValue(&fake_poll_var_);
+
+  // Note that the variables are printed in alphabetical order. Also
+  // see PmEvaluationContextText::SetUp() where the value used for
+  // |evaluation_start| is set.
+  EXPECT_EQ("{\n"
+            "   \"evaluation_start\": \"3/2/2006 1:23:45 GMT\",\n"
+            "   \"variables\": {\n"
+            "      \"fail_var\": \"(no value)\",\n"
+            "      \"fake_int\": \"42\",\n"
+            "      \"fake_poll\": \"Hello \\\"world\\\"!\"\n"
+            "   }\n"
+            "}\n",
+            eval_ctx_->DumpContext());
+}
+
 }  // namespace chromeos_policy_manager