onc_validator_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 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 "chromeos/network/onc/onc_validator.h"
6
7#include <string>
8#include <utility>
9
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/values.h"
13#include "chromeos/network/onc/onc_constants.h"
14#include "chromeos/network/onc/onc_signature.h"
15#include "chromeos/network/onc/onc_test_utils.h"
16#include "chromeos/network/onc/onc_utils.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace chromeos {
20namespace onc {
21
22class ONCValidatorTest : public ::testing::Test {
23 public:
24  // Validate |onc_object| with the given |signature|. The object is considered
25  // to be managed if |managed_onc| is true. A strict validator is used if
26  // |strict| is true. |onc_object| and the resulting repaired object of the
27  // validation is stored, so that expectations can be checked afterwards using
28  // one of the Expect* functions below.
29  void Validate(bool strict,
30                scoped_ptr<base::DictionaryValue> onc_object,
31                const OncValueSignature* signature,
32                bool managed_onc,
33                ONCSource onc_source) {
34    scoped_ptr<Validator> validator;
35    if (strict) {
36      // Create a strict validator that complains about every error.
37      validator.reset(new Validator(true, true, true, managed_onc));
38    } else {
39      // Create a liberal validator that ignores or repairs non-critical errors.
40      validator.reset(new Validator(false, false, false, managed_onc));
41    }
42    validator->SetOncSource(onc_source);
43    original_object_ = onc_object.Pass();
44    repaired_object_ = validator->ValidateAndRepairObject(signature,
45                                                          *original_object_,
46                                                          &validation_result_);
47  }
48
49  void ExpectValid() {
50    EXPECT_EQ(Validator::VALID, validation_result_);
51    EXPECT_TRUE(test_utils::Equals(original_object_.get(),
52                                   repaired_object_.get()));
53  }
54
55  void ExpectRepairWithWarnings(
56      const base::DictionaryValue& expected_repaired) {
57    EXPECT_EQ(Validator::VALID_WITH_WARNINGS, validation_result_);
58    EXPECT_TRUE(test_utils::Equals(&expected_repaired, repaired_object_.get()));
59  }
60
61  void ExpectInvalid() {
62    EXPECT_EQ(Validator::INVALID, validation_result_);
63    EXPECT_EQ(NULL, repaired_object_.get());
64  }
65
66 private:
67  Validator::Result validation_result_;
68  scoped_ptr<const base::DictionaryValue> original_object_;
69  scoped_ptr<const base::DictionaryValue> repaired_object_;
70};
71
72namespace {
73
74struct OncParams {
75  // |location_of_object| is a string to identify the object to be tested. It
76  // may be used as a filename or as a dictionary key.
77  OncParams(const std::string& location_of_object,
78            const OncValueSignature* onc_signature,
79            bool is_managed_onc,
80            ONCSource onc_source = ONC_SOURCE_NONE)
81      : location(location_of_object),
82        signature(onc_signature),
83        is_managed(is_managed_onc),
84        onc_source(onc_source) {
85  }
86
87  std::string location;
88  const OncValueSignature* signature;
89  bool is_managed;
90  ONCSource onc_source;
91};
92
93::std::ostream& operator<<(::std::ostream& os, const OncParams& onc) {
94  return os << "(" << onc.location << ", " << onc.signature << ", "
95            << (onc.is_managed ? "managed" : "unmanaged") << ", "
96            << GetSourceAsString(onc.onc_source) << ")";
97}
98
99}  // namespace
100
101// Ensure that the constant |kEmptyUnencryptedConfiguration| describes a valid
102// ONC toplevel object.
103TEST_F(ONCValidatorTest, EmptyUnencryptedConfiguration) {
104  Validate(true, ReadDictionaryFromJson(kEmptyUnencryptedConfiguration),
105           &kToplevelConfigurationSignature, false, ONC_SOURCE_NONE);
106  ExpectValid();
107}
108
109// This test case is about validating valid ONC objects without any errors. Both
110// the strict and the liberal validator accept the object.
111class ONCValidatorValidTest : public ONCValidatorTest,
112                              public ::testing::WithParamInterface<OncParams> {
113};
114
115TEST_P(ONCValidatorValidTest, StrictValidationValid) {
116  OncParams onc = GetParam();
117  Validate(true, test_utils::ReadTestDictionary(onc.location), onc.signature,
118           onc.is_managed, onc.onc_source);
119  ExpectValid();
120}
121
122TEST_P(ONCValidatorValidTest, LiberalValidationValid) {
123  OncParams onc = GetParam();
124  Validate(false, test_utils::ReadTestDictionary(onc.location), onc.signature,
125           onc.is_managed, onc.onc_source);
126  ExpectValid();
127}
128
129// The parameters are:
130// OncParams(string: Filename of a ONC file that is to be validated,
131//           OncValueSignature: signature of that ONC,
132//           bool: true if the ONC is managed).
133INSTANTIATE_TEST_CASE_P(
134    ONCValidatorValidTest,
135    ONCValidatorValidTest,
136    ::testing::Values(OncParams("managed_toplevel1.onc",
137                                &kToplevelConfigurationSignature,
138                                true),
139                      OncParams("managed_toplevel2.onc",
140                                &kToplevelConfigurationSignature,
141                                true),
142                      // Check that at least one configuration is accepted for
143                      // device policies.
144                      OncParams("managed_toplevel_wifi_peap.onc",
145                                &kToplevelConfigurationSignature,
146                                true,
147                                ONC_SOURCE_DEVICE_POLICY),
148                      OncParams("toplevel_wifi_wpa_psk.onc",
149                                &kToplevelConfigurationSignature,
150                                false),
151                      OncParams("encrypted.onc",
152                                &kToplevelConfigurationSignature,
153                                true),
154                      OncParams("managed_vpn.onc",
155                                &kNetworkConfigurationSignature,
156                                true),
157                      OncParams("managed_ethernet.onc",
158                                &kNetworkConfigurationSignature,
159                                true),
160                      OncParams("translation_of_shill_wifi_with_state.onc",
161                                &kNetworkWithStateSignature,
162                                false)));
163
164namespace {
165
166struct RepairParams {
167  // Both arguments are strings to identify the object that is expected as the
168  // validation result. They may either be used as filenames or as dictionary
169  // keys.
170  RepairParams(std::string strict_repaired,
171               std::string liberal_repaired)
172      : location_of_strict_repaired(strict_repaired),
173        location_of_liberal_repaired(liberal_repaired) {
174  }
175
176  std::string location_of_strict_repaired;
177  std::string location_of_liberal_repaired;
178};
179
180::std::ostream& operator<<(::std::ostream& os, const RepairParams& rp) {
181  return os << "(" << rp.location_of_strict_repaired << ", "
182            << rp.location_of_liberal_repaired << ")";
183}
184
185}  // namespace
186
187// This test case is about validating ONC objects that contain errors which can
188// be repaired (then the errors count as warnings). If a location of the
189// expected repaired object is given, then it is checked that the validator
190// (either strict or liberal) returns this repaired object and the result is
191// VALID_WITH_WARNINGS. If the location is the empty string, then it is expected
192// that the validator returns NULL and the result INVALID.
193class ONCValidatorTestRepairable
194    : public ONCValidatorTest,
195      public ::testing::WithParamInterface<std::pair<OncParams,
196                                                     RepairParams> > {
197 public:
198  // Load the common test data and return the dictionary at the field with
199  // name |name|.
200  scoped_ptr<base::DictionaryValue> GetDictionaryFromTestFile(
201      const std::string &name) {
202    scoped_ptr<const base::DictionaryValue> dict(
203        test_utils::ReadTestDictionary("invalid_settings_with_repairs.json"));
204    const base::DictionaryValue* onc_object = NULL;
205    CHECK(dict->GetDictionary(name, &onc_object));
206    return make_scoped_ptr(onc_object->DeepCopy());
207  }
208};
209
210TEST_P(ONCValidatorTestRepairable, StrictValidation) {
211  OncParams onc = GetParam().first;
212  Validate(true, GetDictionaryFromTestFile(onc.location), onc.signature,
213           onc.is_managed, onc.onc_source);
214  std::string location_of_repaired =
215      GetParam().second.location_of_strict_repaired;
216  if (location_of_repaired.empty())
217    ExpectInvalid();
218  else
219    ExpectRepairWithWarnings(*GetDictionaryFromTestFile(location_of_repaired));
220}
221
222TEST_P(ONCValidatorTestRepairable, LiberalValidation) {
223  OncParams onc = GetParam().first;
224  Validate(false, GetDictionaryFromTestFile(onc.location), onc.signature,
225           onc.is_managed, onc.onc_source);
226  std::string location_of_repaired =
227      GetParam().second.location_of_liberal_repaired;
228  if (location_of_repaired.empty())
229    ExpectInvalid();
230  else
231    ExpectRepairWithWarnings(*GetDictionaryFromTestFile(location_of_repaired));
232}
233
234// The parameters for all test case instantations below are:
235// OncParams(string: A fieldname in the dictionary from the file
236//                   "invalid_settings_with_repairs.json". That nested
237//                   dictionary will be tested.
238//           OncValueSignature: signature of that ONC,
239//           bool: true if the ONC is managed).
240// RepairParams(string: A fieldname in the dictionary from the file
241//                      "invalid_settings_with_repairs.json". That nested
242//                      dictionary is the expected result from strict
243//                      validation,
244//              string: A fieldname in the dictionary from the file
245//                      "invalid_settings_with_repairs.json". That nested
246//                      dictionary is the expected result from liberal
247//                      validation).
248
249// Strict validator returns INVALID. Liberal validator repairs.
250INSTANTIATE_TEST_CASE_P(
251    StrictInvalidLiberalRepair,
252    ONCValidatorTestRepairable,
253    ::testing::Values(
254         std::make_pair(OncParams("network-unknown-fieldname",
255                                  &kNetworkConfigurationSignature,
256                                  false),
257                        RepairParams("", "network-repaired")),
258         std::make_pair(OncParams("managed-network-unknown-fieldname",
259                                  &kNetworkConfigurationSignature,
260                                  true),
261                        RepairParams("", "managed-network-repaired")),
262         std::make_pair(OncParams("managed-network-unknown-recommended",
263                                  &kNetworkConfigurationSignature,
264                                  true),
265                        RepairParams("", "managed-network-repaired")),
266         std::make_pair(OncParams("managed-network-dict-recommended",
267                                  &kNetworkConfigurationSignature,
268                                  true),
269                        RepairParams("", "managed-network-repaired")),
270         std::make_pair(OncParams("network-missing-required",
271                                  &kNetworkConfigurationSignature,
272                                  false),
273                        RepairParams("", "network-missing-required")),
274         std::make_pair(OncParams("managed-network-missing-required",
275                                  &kNetworkConfigurationSignature,
276                                  true),
277                        RepairParams("", "managed-network-missing-required")),
278         // Ensure that state values from Shill aren't accepted as
279         // configuration.
280         std::make_pair(OncParams("network-state-field",
281                                  &kNetworkConfigurationSignature,
282                                  false),
283                        RepairParams("", "network-repaired")),
284         std::make_pair(OncParams("network-nested-state-field",
285                                  &kNetworkConfigurationSignature,
286                                  false),
287                        RepairParams("",
288                                     "network-nested-state-field-repaired")),
289         std::make_pair(OncParams("toplevel-with-repairable-networks",
290                                  &kToplevelConfigurationSignature,
291                                  false,
292                                  ONC_SOURCE_DEVICE_POLICY),
293                        RepairParams("", "toplevel-with-repaired-networks"))));
294
295// Strict and liberal validator repair identically.
296INSTANTIATE_TEST_CASE_P(
297    StrictAndLiberalRepairIdentically,
298    ONCValidatorTestRepairable,
299    ::testing::Values(
300         std::make_pair(OncParams("toplevel-invalid-network",
301                                  &kToplevelConfigurationSignature,
302                                  false),
303                        RepairParams("toplevel-repaired",
304                                     "toplevel-repaired")),
305         std::make_pair(OncParams("toplevel-invalid-network",
306                                  &kToplevelConfigurationSignature,
307                                  true),
308                        RepairParams("toplevel-repaired",
309                                     "toplevel-repaired")),
310         // Ignore recommended arrays in unmanaged ONC.
311         std::make_pair(OncParams("network-with-illegal-recommended",
312                                  &kNetworkConfigurationSignature,
313                                  false),
314                        RepairParams("network-repaired", "network-repaired")),
315         std::make_pair(OncParams("toplevel-with-vpn",
316                                  &kToplevelConfigurationSignature,
317                                  false,
318                                  ONC_SOURCE_DEVICE_POLICY),
319                        RepairParams("toplevel-empty", "toplevel-empty")),
320         std::make_pair(OncParams("toplevel-with-server-and-ca-cert",
321                                  &kToplevelConfigurationSignature,
322                                  true,
323                                  ONC_SOURCE_DEVICE_POLICY),
324                        RepairParams("toplevel-server-and-ca-cert-dropped",
325                                     "toplevel-server-and-ca-cert-dropped"))));
326
327// Strict and liberal validator both repair, but with different results.
328INSTANTIATE_TEST_CASE_P(
329    StrictAndLiberalRepairDifferently,
330    ONCValidatorTestRepairable,
331    ::testing::Values(
332         std::make_pair(OncParams("toplevel-with-nested-warning",
333                                  &kToplevelConfigurationSignature,
334                                  false),
335                        RepairParams("toplevel-empty", "toplevel-repaired"))));
336
337// Strict and liberal validator return both INVALID.
338INSTANTIATE_TEST_CASE_P(
339    StrictAndLiberalInvalid,
340    ONCValidatorTestRepairable,
341    ::testing::Values(
342         std::make_pair(OncParams("network-unknown-value",
343                                  &kNetworkConfigurationSignature, false),
344                        RepairParams("", "")),
345         std::make_pair(OncParams("managed-network-unknown-value",
346                                  &kNetworkConfigurationSignature, true),
347                        RepairParams("", "")),
348         std::make_pair(OncParams("network-value-out-of-range",
349                                  &kNetworkConfigurationSignature, false),
350                        RepairParams("", "")),
351         std::make_pair(OncParams("managed-network-value-out-of-range",
352                                  &kNetworkConfigurationSignature, true),
353                        RepairParams("", "")),
354         std::make_pair(OncParams("network-wrong-type",
355                                  &kNetworkConfigurationSignature, false),
356                        RepairParams("", "")),
357         std::make_pair(OncParams("managed-network-wrong-type",
358                                  &kNetworkConfigurationSignature, true),
359                        RepairParams("", "")),
360         std::make_pair(OncParams("network-with-client-cert-pattern",
361                                  &kNetworkConfigurationSignature, true,
362                                  ONC_SOURCE_DEVICE_POLICY),
363                        RepairParams("", ""))));
364
365}  // namespace onc
366}  // namespace chromeos
367