diff options
author | binjin@chromium.org <binjin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-09 17:51:43 +0000 |
---|---|---|
committer | binjin@chromium.org <binjin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-09 17:51:43 +0000 |
commit | b245d6aa8ed382b85237d8157fad7309d3670dbf (patch) | |
tree | eef497a7eb9dd9866da9e2c703e8674ff1fcbd66 /components | |
parent | 1c3626ee7aa7f098e70aef46c2a14b8a68e2251b (diff) | |
download | chromium_src-b245d6aa8ed382b85237d8157fad7309d3670dbf.zip chromium_src-b245d6aa8ed382b85237d8157fad7309d3670dbf.tar.gz chromium_src-b245d6aa8ed382b85237d8157fad7309d3670dbf.tar.bz2 |
Add $ref support to policy schema
BUG=347082
Review URL: https://codereview.chromium.org/228423002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@262738 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
3 files changed, 109 insertions, 72 deletions
diff --git a/components/policy/core/common/generate_policy_source_unittest.cc b/components/policy/core/common/generate_policy_source_unittest.cc index a2b1462..108b568 100644 --- a/components/policy/core/common/generate_policy_source_unittest.cc +++ b/components/policy/core/common/generate_policy_source_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstring> #include <string> #include "base/memory/scoped_ptr.h" @@ -17,6 +18,40 @@ namespace policy { +namespace { + +// Checks if two schemas are the same or not. Note that this function doesn't +// consider restrictions on integers and strings nor pattern properties. +bool IsSameSchema(Schema a, Schema b) { + if (a.valid() != b.valid()) + return false; + if (!a.valid()) + return true; + if (a.type() != b.type()) + return false; + if (a.type() == base::Value::TYPE_LIST) + return IsSameSchema(a.GetItems(), b.GetItems()); + if (a.type() != base::Value::TYPE_DICTIONARY) + return true; + Schema::Iterator a_it = a.GetPropertiesIterator(); + Schema::Iterator b_it = b.GetPropertiesIterator(); + while (!a_it.IsAtEnd()) { + if (b_it.IsAtEnd()) + return false; + if (strcmp(a_it.key(), b_it.key()) != 0) + return false; + if (!IsSameSchema(a_it.schema(), b_it.schema())) + return false; + a_it.Advance(); + b_it.Advance(); + } + if (!b_it.IsAtEnd()) + return false; + return IsSameSchema(a.GetAdditionalProperties(), b.GetAdditionalProperties()); +} + +} // namespace + TEST(GeneratePolicySource, ChromeSchemaData) { Schema schema = Schema::Wrap(GetChromeSchemaData()); ASSERT_TRUE(schema.valid()); @@ -83,6 +118,20 @@ TEST(GeneratePolicySource, ChromeSchemaData) { EXPECT_EQ(base::Value::TYPE_STRING, it.schema().type()); } EXPECT_TRUE(*next == NULL); + +#if defined(OS_CHROMEOS) + subschema = schema.GetKnownProperty(key::kPowerManagementIdleSettings); + ASSERT_TRUE(subschema.valid()); + + EXPECT_TRUE(IsSameSchema(subschema.GetKnownProperty("AC"), + subschema.GetKnownProperty("Battery"))); + + subschema = schema.GetKnownProperty(key::kDeviceLoginScreenPowerManagement); + ASSERT_TRUE(subschema.valid()); + + EXPECT_TRUE(IsSameSchema(subschema.GetKnownProperty("AC"), + subschema.GetKnownProperty("Battery"))); +#endif } TEST(GeneratePolicySource, PolicyDetails) { diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 0033a8f..6042bfe 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json @@ -5286,6 +5286,7 @@ 'AC': { 'description': 'Delays and actions to take when the device is idle and running on AC power', 'type': 'object', + 'id': 'PowerManagementDelays', 'properties': { 'Delays': { 'type': 'object', @@ -5321,42 +5322,8 @@ }, 'Battery': { 'description': 'Delays and actions to take when the device is idle and running on battery', - 'type': 'object', - # TODO(binjin): Use $ref placeholder here once generated policy - # constants get full support of it. http://crbug.com/347082 - 'properties': { - 'Delays': { - 'type': 'object', - 'properties': { - 'ScreenDim': { - 'description': 'The length of time without user input after which the screen is dimmed, in milliseconds', - 'type': 'integer', - 'minimum': 0 - }, - 'ScreenOff': { - 'description': 'The length of time without user input after which the screen is turned off, in milliseconds', - 'type': 'integer', - 'minimum': 0 - }, - 'IdleWarning': { - 'description': 'The length of time without user input after which a warning dialog is shown, in milliseconds', - 'type': 'integer', - 'minimum': 0 - }, - 'Idle': { - 'description': 'The length of time without user input after which the idle action is taken, in milliseconds', - 'type': 'integer', - 'minimum': 0 - } - } - }, - 'IdleAction': { - 'description': 'Action to take when the idle delay is reached', - 'type': 'string', - 'enum': [ 'Suspend', 'Logout', 'Shutdown', 'DoNothing' ] - } - } - }, + '$ref': 'PowerManagementDelays' + } } }, 'supported_on': ['chrome_os:35-'], @@ -5453,6 +5420,7 @@ 'AC': { 'description': 'Power management settings applicable only when running on AC power', 'type': 'object', + 'id': 'DeviceLoginScreenPowerSettings', 'properties': { 'Delays': { 'type': 'object', @@ -5483,34 +5451,7 @@ }, 'Battery': { 'description': 'Power management settings applicable only when running on battery power', - 'type': 'object', - 'properties': { - 'Delays': { - 'type': 'object', - 'properties': { - 'ScreenDim': { - 'description': 'The length of time without user input after which the screen is dimmed, in milliseconds', - 'type': 'integer', - 'minimum': 0 - }, - 'ScreenOff': { - 'description': 'The length of time without user input after which the screen is turned off, in milliseconds', - 'type': 'integer', - 'minimum': 0 - }, - 'Idle': { - 'description': 'The length of time without user input after which the idle action is taken, in milliseconds', - 'type': 'integer', - 'minimum': 0 - } - } - }, - 'IdleAction': { - 'description': 'Action to take when the idle delay is reached', - 'type': 'string', - 'enum': [ 'Suspend', 'Shutdown', 'DoNothing' ] - } - } + '$ref': 'DeviceLoginScreenPowerSettings' }, 'LidCloseAction': { 'description': 'Action to take when the lid is closed', diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py index 9ccf881..0be012a 100755 --- a/components/policy/tools/generate_policy_source.py +++ b/components/policy/tools/generate_policy_source.py @@ -11,11 +11,13 @@ chromium_os_flag should be 1 if this is a Chromium OS build template is the path to a .json policy template file.''' from __future__ import with_statement +from functools import partial import json from optparse import OptionParser import re import sys import textwrap +import types CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' @@ -282,6 +284,7 @@ class SchemaNodesGenerator: } self.stringlist_type = None self.ranges = {} + self.id_map = {} def GetString(self, s): if s in self.shared_strings: @@ -398,6 +401,12 @@ class SchemaNodesGenerator: |schema|: a valid JSON schema in a dictionary. |name|: the name of the current node, for the generated comments.""" + if schema.has_key('$ref'): + if schema.has_key('id'): + raise RuntimeError("Schemas with a $ref can't have an id") + if not isinstance(schema['$ref'], types.StringTypes): + raise RuntimeError("$ref attribute must be a string") + return schema['$ref'] if schema['type'] in self.simple_types: if not self.SchemaHaveRestriction(schema): # Simple types use shared nodes. @@ -413,9 +422,8 @@ class SchemaNodesGenerator: # Special case for lists of strings, which is a common policy type. if schema['items']['type'] == 'string': return self.GetStringList() - return self.AppendSchema( - 'TYPE_LIST', - self.Generate(schema['items'], 'items of ' + name)) + return self.AppendSchema('TYPE_LIST', + self.GenerateAndCollectID(schema['items'], 'items of ' + name)) elif schema['type'] == 'object': # Reserve an index first, so that dictionaries come before their # properties. This makes sure that the root node is the first in the @@ -423,7 +431,7 @@ class SchemaNodesGenerator: index = self.AppendSchema('TYPE_DICTIONARY', -1) if 'additionalProperties' in schema: - additionalProperties = self.Generate( + additionalProperties = self.GenerateAndCollectID( schema['additionalProperties'], 'additionalProperties of ' + name) else: @@ -434,13 +442,14 @@ class SchemaNodesGenerator: # recursive calls to Generate() append the necessary child nodes; if # |properties| were a generator then this wouldn't work. sorted_properties = sorted(schema.get('properties', {}).items()) - properties = [ (self.GetString(key), self.Generate(subschema, key)) - for key, subschema in sorted_properties ] + properties = [ + (self.GetString(key), self.GenerateAndCollectID(subschema, key)) + for key, subschema in sorted_properties ] pattern_properties = [] for pattern, subschema in schema.get('patternProperties', {}).items(): pattern_properties.append((self.GetString(pattern), - self.Generate(subschema, pattern))); + self.GenerateAndCollectID(subschema, pattern))); begin = len(self.property_nodes) self.property_nodes += properties @@ -462,6 +471,20 @@ class SchemaNodesGenerator: else: assert False + def GenerateAndCollectID(self, schema, name): + """A wrapper of Generate(), will take the return value, check and add 'id' + attribute to self.id_map. The wrapper needs to be used for every call to + Generate(). + """ + index = self.Generate(schema, name) + if not schema.has_key('id'): + return index + id_str = schema['id'] + if self.id_map.has_key(id_str): + raise RuntimeError('Duplicated id: ' + id_str) + self.id_map[id_str] = index + return index + def Write(self, f): """Writes the generated structs to the given file. @@ -516,6 +539,29 @@ class SchemaNodesGenerator: f.write(' kStringEnumerations,\n' if self.string_enums else ' NULL,\n') f.write('};\n\n') + def GetByID(self, id_str): + if not isinstance(id_str, types.StringTypes): + return id_str + if not self.id_map.has_key(id_str): + raise RuntimeError('Invalid $ref: ' + id_str) + return self.id_map[id_str] + + def ResolveID(self, index, params): + return params[:index] + (self.GetByID(params[index]),) + params[index+1:] + + def ResolveReferences(self): + """Resolve reference mapping, required to be called after Generate() + + After calling Generate(), the type of indices used in schema structures + might be either int or string. An int type suggests that it's a resolved + index, but for string type it's unresolved. Resolving a reference is as + simple as looking up for corresponding ID in self.id_map, and replace the + old index with the mapped index. + """ + self.schema_nodes = map(partial(self.ResolveID, 1), self.schema_nodes) + self.property_nodes = map(partial(self.ResolveID, 1), self.property_nodes) + self.properties_nodes = map(partial(self.ResolveID, 3), + self.properties_nodes) def _WritePolicyConstantSource(policies, os, f): f.write('#include "policy/policy_constants.h"\n' @@ -558,7 +604,8 @@ def _WritePolicyConstantSource(policies, os, f): f.write('};\n\n') schema_generator = SchemaNodesGenerator(shared_strings) - schema_generator.Generate(chrome_schema, 'root node') + schema_generator.GenerateAndCollectID(chrome_schema, 'root node') + schema_generator.ResolveReferences() schema_generator.Write(f) f.write('bool CompareKeys(const internal::PropertyNode& node,\n' |