Home | History | Annotate | Download | only in incident_reporting
      1 // Copyright 2014 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 "chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/compiler_specific.h"
     12 #include "base/memory/scoped_vector.h"
     13 #include "base/values.h"
     14 #include "chrome/common/safe_browsing/csd.pb.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 // A basic test harness that creates a delegate instance for which it stores all
     18 // incidents. Tests can push data to the delegate and verify that the test
     19 // instance was provided with the expected data.
     20 class PreferenceValidationDelegateTest : public testing::Test {
     21  protected:
     22   typedef ScopedVector<safe_browsing::ClientIncidentReport_IncidentData>
     23       IncidentVector;
     24 
     25   PreferenceValidationDelegateTest()
     26       : kPrefPath_("atomic.pref"),
     27         null_value_(base::Value::CreateNullValue()) {}
     28 
     29   virtual void SetUp() OVERRIDE {
     30     testing::Test::SetUp();
     31     invalid_keys_.push_back(std::string("one"));
     32     invalid_keys_.push_back(std::string("two"));
     33     instance_.reset(new safe_browsing::PreferenceValidationDelegate(
     34         base::Bind(&PreferenceValidationDelegateTest::AddIncident,
     35                    base::Unretained(this))));
     36   }
     37 
     38   void AddIncident(
     39       scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> data) {
     40     incidents_.push_back(data.release());
     41   }
     42 
     43   static void ExpectValueStatesEquate(
     44       PrefHashStoreTransaction::ValueState store_state,
     45       safe_browsing::
     46           ClientIncidentReport_IncidentData_TrackedPreferenceIncident_ValueState
     47               incident_state) {
     48     typedef safe_browsing::
     49         ClientIncidentReport_IncidentData_TrackedPreferenceIncident TPIncident;
     50     switch (store_state) {
     51       case PrefHashStoreTransaction::CLEARED:
     52         EXPECT_EQ(TPIncident::CLEARED, incident_state);
     53         break;
     54       case PrefHashStoreTransaction::CHANGED:
     55         EXPECT_EQ(TPIncident::CHANGED, incident_state);
     56         break;
     57       case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE:
     58         EXPECT_EQ(TPIncident::UNTRUSTED_UNKNOWN_VALUE, incident_state);
     59         break;
     60       default:
     61         FAIL() << "unexpected store state";
     62         break;
     63     }
     64   }
     65 
     66   static void ExpectKeysEquate(
     67       const std::vector<std::string>& store_keys,
     68       const google::protobuf::RepeatedPtrField<std::string>& incident_keys) {
     69     ASSERT_EQ(store_keys.size(), static_cast<size_t>(incident_keys.size()));
     70     for (int i = 0; i < incident_keys.size(); ++i) {
     71       EXPECT_EQ(store_keys[i], incident_keys.Get(i));
     72     }
     73   }
     74 
     75   const std::string kPrefPath_;
     76   IncidentVector incidents_;
     77   scoped_ptr<base::Value> null_value_;
     78   base::DictionaryValue dict_value_;
     79   std::vector<std::string> invalid_keys_;
     80   scoped_ptr<TrackedPreferenceValidationDelegate> instance_;
     81 };
     82 
     83 // Tests that a NULL value results in an incident with no value.
     84 TEST_F(PreferenceValidationDelegateTest, NullValue) {
     85   instance_->OnAtomicPreferenceValidation(kPrefPath_,
     86                                           NULL,
     87                                           PrefHashStoreTransaction::CLEARED,
     88                                           TrackedPreferenceHelper::DONT_RESET);
     89   safe_browsing::ClientIncidentReport_IncidentData* incident =
     90       incidents_.back();
     91   EXPECT_FALSE(incident->tracked_preference().has_atomic_value());
     92   EXPECT_EQ(
     93       safe_browsing::
     94           ClientIncidentReport_IncidentData_TrackedPreferenceIncident::CLEARED,
     95       incident->tracked_preference().value_state());
     96 }
     97 
     98 // Tests that all supported value types can be stringified into an incident. The
     99 // parameters for the test are the type of value to test and the expected value
    100 // string.
    101 class PreferenceValidationDelegateValues
    102     : public PreferenceValidationDelegateTest,
    103       public testing::WithParamInterface<
    104           std::tr1::tuple<base::Value::Type, const char*> > {
    105  protected:
    106   virtual void SetUp() OVERRIDE {
    107     PreferenceValidationDelegateTest::SetUp();
    108     value_type_ = std::tr1::get<0>(GetParam());
    109     expected_value_ = std::tr1::get<1>(GetParam());
    110   }
    111 
    112   static scoped_ptr<base::Value> MakeValue(base::Value::Type value_type) {
    113     using base::Value;
    114     switch (value_type) {
    115       case Value::TYPE_NULL:
    116         return make_scoped_ptr(Value::CreateNullValue());
    117       case Value::TYPE_BOOLEAN:
    118         return scoped_ptr<Value>(new base::FundamentalValue(false));
    119       case Value::TYPE_INTEGER:
    120         return scoped_ptr<Value>(new base::FundamentalValue(47));
    121       case Value::TYPE_DOUBLE:
    122         return scoped_ptr<Value>(new base::FundamentalValue(0.47));
    123       case Value::TYPE_STRING:
    124         return scoped_ptr<Value>(new base::StringValue("i have a spleen"));
    125       case Value::TYPE_DICTIONARY: {
    126         scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
    127         value->SetInteger("twenty-two", 22);
    128         value->SetInteger("forty-seven", 47);
    129         return value.PassAs<Value>();
    130       }
    131       case Value::TYPE_LIST: {
    132         scoped_ptr<base::ListValue> value(new base::ListValue());
    133         value->AppendInteger(22);
    134         value->AppendInteger(47);
    135         return value.PassAs<Value>();
    136       }
    137       default:
    138         ADD_FAILURE() << "unsupported value type " << value_type;
    139     }
    140     return scoped_ptr<Value>();
    141   }
    142 
    143   base::Value::Type value_type_;
    144   const char* expected_value_;
    145 };
    146 
    147 TEST_P(PreferenceValidationDelegateValues, Value) {
    148   instance_->OnAtomicPreferenceValidation(kPrefPath_,
    149                                           MakeValue(value_type_).get(),
    150                                           PrefHashStoreTransaction::CLEARED,
    151                                           TrackedPreferenceHelper::DONT_RESET);
    152   ASSERT_EQ(1U, incidents_.size());
    153   safe_browsing::ClientIncidentReport_IncidentData* incident =
    154       incidents_.back();
    155   EXPECT_EQ(std::string(expected_value_),
    156             incident->tracked_preference().atomic_value());
    157 }
    158 
    159 INSTANTIATE_TEST_CASE_P(
    160     Values,
    161     PreferenceValidationDelegateValues,
    162     // On Android, make_tuple(..., "null") doesn't compile due to the error:
    163     // testing/gtest/include/gtest/internal/gtest-tuple.h:246:48:
    164     //   error: array used as initializer
    165     testing::Values(
    166         std::tr1::make_tuple(base::Value::TYPE_NULL,
    167                              const_cast<char*>("null")),
    168         std::tr1::make_tuple(base::Value::TYPE_BOOLEAN,
    169                              const_cast<char*>("false")),
    170         std::tr1::make_tuple(base::Value::TYPE_INTEGER,
    171                              const_cast<char*>("47")),
    172         std::tr1::make_tuple(base::Value::TYPE_DOUBLE,
    173                              const_cast<char*>("0.47")),
    174         std::tr1::make_tuple(base::Value::TYPE_STRING,
    175                              const_cast<char*>("i have a spleen")),
    176         std::tr1::make_tuple(base::Value::TYPE_DICTIONARY,
    177             const_cast<char*>("{\"forty-seven\":47,\"twenty-two\":22}")),
    178         std::tr1::make_tuple(base::Value::TYPE_LIST,
    179                              const_cast<char*>("[22,47]"))));
    180 
    181 // Tests that no incidents are reported for relevant combinations of ValueState.
    182 class PreferenceValidationDelegateNoIncident
    183     : public PreferenceValidationDelegateTest,
    184       public testing::WithParamInterface<PrefHashStoreTransaction::ValueState> {
    185  protected:
    186   virtual void SetUp() OVERRIDE {
    187     PreferenceValidationDelegateTest::SetUp();
    188     value_state_ = GetParam();
    189   }
    190 
    191   PrefHashStoreTransaction::ValueState value_state_;
    192 };
    193 
    194 TEST_P(PreferenceValidationDelegateNoIncident, Atomic) {
    195   instance_->OnAtomicPreferenceValidation(kPrefPath_,
    196                                           null_value_.get(),
    197                                           value_state_,
    198                                           TrackedPreferenceHelper::DONT_RESET);
    199   EXPECT_EQ(0U, incidents_.size());
    200 }
    201 
    202 TEST_P(PreferenceValidationDelegateNoIncident, Split) {
    203   instance_->OnSplitPreferenceValidation(kPrefPath_,
    204                                          &dict_value_,
    205                                          invalid_keys_,
    206                                          value_state_,
    207                                          TrackedPreferenceHelper::DONT_RESET);
    208   EXPECT_EQ(0U, incidents_.size());
    209 }
    210 
    211 INSTANTIATE_TEST_CASE_P(
    212     NoIncident,
    213     PreferenceValidationDelegateNoIncident,
    214     testing::Values(PrefHashStoreTransaction::UNCHANGED,
    215                     PrefHashStoreTransaction::SECURE_LEGACY,
    216                     PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE));
    217 
    218 // Tests that incidents are reported for relevant combinations of ValueState and
    219 // ResetAction.
    220 class PreferenceValidationDelegateWithIncident
    221     : public PreferenceValidationDelegateTest,
    222       public testing::WithParamInterface<
    223           std::tr1::tuple<PrefHashStoreTransaction::ValueState,
    224                           TrackedPreferenceHelper::ResetAction> > {
    225  protected:
    226   virtual void SetUp() OVERRIDE {
    227     PreferenceValidationDelegateTest::SetUp();
    228     value_state_ = std::tr1::get<0>(GetParam());
    229     reset_action_ = std::tr1::get<1>(GetParam());
    230   }
    231 
    232   PrefHashStoreTransaction::ValueState value_state_;
    233   TrackedPreferenceHelper::ResetAction reset_action_;
    234 };
    235 
    236 TEST_P(PreferenceValidationDelegateWithIncident, Atomic) {
    237   instance_->OnAtomicPreferenceValidation(
    238       kPrefPath_, null_value_.get(), value_state_, reset_action_);
    239   ASSERT_EQ(1U, incidents_.size());
    240   safe_browsing::ClientIncidentReport_IncidentData* incident =
    241       incidents_.back();
    242   EXPECT_TRUE(incident->has_tracked_preference());
    243   const safe_browsing::
    244       ClientIncidentReport_IncidentData_TrackedPreferenceIncident& tp_incident =
    245           incident->tracked_preference();
    246   EXPECT_EQ(kPrefPath_, tp_incident.path());
    247   EXPECT_EQ(0, tp_incident.split_key_size());
    248   EXPECT_TRUE(tp_incident.has_atomic_value());
    249   EXPECT_EQ(std::string("null"), tp_incident.atomic_value());
    250   EXPECT_TRUE(tp_incident.has_value_state());
    251   ExpectValueStatesEquate(value_state_, tp_incident.value_state());
    252 }
    253 
    254 TEST_P(PreferenceValidationDelegateWithIncident, Split) {
    255   instance_->OnSplitPreferenceValidation(
    256       kPrefPath_, &dict_value_, invalid_keys_, value_state_, reset_action_);
    257   ASSERT_EQ(1U, incidents_.size());
    258   safe_browsing::ClientIncidentReport_IncidentData* incident =
    259       incidents_.back();
    260   EXPECT_TRUE(incident->has_tracked_preference());
    261   const safe_browsing::
    262       ClientIncidentReport_IncidentData_TrackedPreferenceIncident& tp_incident =
    263           incident->tracked_preference();
    264   EXPECT_EQ(kPrefPath_, tp_incident.path());
    265   EXPECT_FALSE(tp_incident.has_atomic_value());
    266   ExpectKeysEquate(invalid_keys_, tp_incident.split_key());
    267   EXPECT_TRUE(tp_incident.has_value_state());
    268   ExpectValueStatesEquate(value_state_, tp_incident.value_state());
    269 }
    270 
    271 INSTANTIATE_TEST_CASE_P(
    272     WithIncident,
    273     PreferenceValidationDelegateWithIncident,
    274     testing::Combine(
    275         testing::Values(PrefHashStoreTransaction::CLEARED,
    276                         PrefHashStoreTransaction::CHANGED,
    277                         PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE),
    278         testing::Values(TrackedPreferenceHelper::WANTED_RESET,
    279                         TrackedPreferenceHelper::DO_RESET)));
    280